changeset 12016:0248e987199b

PSARC 2009/306 Brussels II - ipadm and libipadm PSARC 2010/080 Brussels II addendum 6827318 Brussels Phase II aka ipadm(1m) 6731945 need BSD getifaddrs() API 6909065 explicitly disallow non-contiguous netmasks in the next minor release 6853922 ifconfig dumps core when ether address is non-hexadecimal. 6815806 ipReasmTimeout value should be variable 6567083 nd_getset has some dead and confusing code. 6884466 remove unused tcp/sctp ndd tunables 6928813 Comments at odds with default value of tcp_time_wait_interval 6236982 ifconfig usesrc lets adapter use itself as source address 6936855 modifying the ip6_strict_src_multihoming to non-zero value will unbind V4 IREs
author Girish Moodalbail <Girish.Moodalbail@Sun.COM>
date Fri, 26 Mar 2010 17:53:11 -0400
parents 63716a810520
children 2ff17b2a8ff9
files exception_lists/packaging usr/src/Makefile.lint usr/src/Targetdirs usr/src/cmd/cmd-inet/lib/Makefile usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h usr/src/cmd/cmd-inet/usr.sbin/Makefile usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl usr/src/cmd/cmd-inet/usr.sbin/ndd.c usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding usr/src/cmd/rcm_daemon/Makefile.com usr/src/cmd/rcm_daemon/common/ip_rcm.c usr/src/cmd/svc/milestone/net-iptun usr/src/cmd/svc/milestone/net-loopback usr/src/cmd/svc/milestone/net-physical usr/src/cmd/svc/seed/Makefile usr/src/cmd/truss/codes.c usr/src/head/Makefile usr/src/head/ifaddrs.h usr/src/lib/Makefile usr/src/lib/brand/solaris10/zone/s10_boot.ksh usr/src/lib/libbc/inc/include/net/if.h usr/src/lib/libinetcfg/common/inetcfg.c usr/src/lib/libinetutil/common/inetutil.c usr/src/lib/libinetutil/common/libinetutil.h usr/src/lib/libinetutil/common/mapfile-vers usr/src/lib/libipadm/Makefile usr/src/lib/libipadm/Makefile.com usr/src/lib/libipadm/common/ipadm_addr.c usr/src/lib/libipadm/common/ipadm_if.c usr/src/lib/libipadm/common/ipadm_ipmgmt.h usr/src/lib/libipadm/common/ipadm_ndpd.c usr/src/lib/libipadm/common/ipadm_ndpd.h usr/src/lib/libipadm/common/ipadm_persist.c usr/src/lib/libipadm/common/ipadm_prop.c usr/src/lib/libipadm/common/libipadm.c usr/src/lib/libipadm/common/libipadm.h usr/src/lib/libipadm/common/libipadm_impl.h usr/src/lib/libipadm/common/llib-lipadm usr/src/lib/libipadm/common/mapfile-vers usr/src/lib/libipadm/i386/Makefile usr/src/lib/libipadm/libipadm.xcl usr/src/lib/libipadm/sparc/Makefile usr/src/lib/libsecdb/auth_attr.txt usr/src/lib/libsecdb/exec_attr.txt usr/src/lib/libsecdb/help/auths/Makefile usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html usr/src/lib/libsecdb/prof_attr.txt usr/src/lib/libsocket/Makefile usr/src/lib/libsocket/Makefile.com usr/src/lib/libsocket/common/libsocket_priv.h usr/src/lib/libsocket/common/llib-lsocket usr/src/lib/libsocket/common/mapfile-vers usr/src/lib/libsocket/inet/getifaddrs.c usr/src/pkg/manifests/SUNWcs.mf usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf usr/src/pkg/manifests/system-header.mf usr/src/pkg/manifests/system-kernel.mf usr/src/pkg/manifests/system-library.mf usr/src/pkg/manifests/system-network.mf usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/inet/Makefile usr/src/uts/common/inet/ip.h usr/src/uts/common/inet/ip/icmp.c usr/src/uts/common/inet/ip/igmp.c usr/src/uts/common/inet/ip/ip.c usr/src/uts/common/inet/ip/ip6_if.c usr/src/uts/common/inet/ip/ip6_ire.c usr/src/uts/common/inet/ip/ip_if.c usr/src/uts/common/inet/ip/ip_ire.c usr/src/uts/common/inet/ip/ip_mroute.c usr/src/uts/common/inet/ip/ip_rts.c usr/src/uts/common/inet/ip/ip_tunables.c usr/src/uts/common/inet/ip_if.h usr/src/uts/common/inet/ip_impl.h usr/src/uts/common/inet/ip_stack.h usr/src/uts/common/inet/nd.c usr/src/uts/common/inet/rawip_impl.h usr/src/uts/common/inet/sctp/sctp.c usr/src/uts/common/inet/sctp/sctp.conf usr/src/uts/common/inet/sctp/sctp6.conf usr/src/uts/common/inet/sctp/sctp6ddi.c usr/src/uts/common/inet/sctp/sctp_impl.h usr/src/uts/common/inet/sctp/sctp_ioc.c usr/src/uts/common/inet/sctp/sctp_param.c usr/src/uts/common/inet/sctp/sctp_stack.h usr/src/uts/common/inet/sctp/sctp_tunables.c usr/src/uts/common/inet/sctp/sctpddi.c usr/src/uts/common/inet/sctp_ip.h usr/src/uts/common/inet/tcp/tcp.c usr/src/uts/common/inet/tcp/tcp_misc.c usr/src/uts/common/inet/tcp/tcp_output.c usr/src/uts/common/inet/tcp/tcp_tunables.c usr/src/uts/common/inet/tcp_impl.h usr/src/uts/common/inet/tcp_stack.h usr/src/uts/common/inet/tunables.c usr/src/uts/common/inet/tunables.h usr/src/uts/common/inet/udp/udp.c usr/src/uts/common/inet/udp/udp_tunables.c usr/src/uts/common/inet/udp_impl.h usr/src/uts/common/io/strplumb.c usr/src/uts/common/net/if.h usr/src/uts/common/sys/sockio.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/ip/ip.global-objs.debug64 usr/src/uts/intel/ip/ip.global-objs.obj64 usr/src/uts/intel/sctp/Makefile usr/src/uts/intel/sctp6/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/ip/ip.global-objs.debug64 usr/src/uts/sparc/ip/ip.global-objs.obj64 usr/src/uts/sparc/sctp/Makefile usr/src/uts/sparc/sctp6/Makefile
diffstat 132 files changed, 20850 insertions(+), 4230 deletions(-) [+]
line wrap: on
line diff
--- a/exception_lists/packaging	Fri Mar 26 14:31:08 2010 -0700
+++ b/exception_lists/packaging	Fri Mar 26 17:53:11 2010 -0400
@@ -113,6 +113,19 @@
 usr/include/sys/vnic.h
 usr/include/sys/vnic_impl.h
 #
+# Private libipadm lint library and header files
+#
+usr/include/ipadm_ipmgmt.h
+usr/include/ipadm_ndpd.h
+usr/include/libipadm.h
+lib/llib-lipadm
+lib/llib-lipadm.ln
+lib/libipadm.so
+#
+# Private libsocket header file
+#
+usr/include/libsocket_priv.h
+#
 # IKE and IPsec support library exceptions.  The IKE support
 # library contains exclusively private interfaces, as does
 # libipsecutil.  My apologies for the glut of header files here.
--- a/usr/src/Makefile.lint	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/Makefile.lint	Fri Mar 26 17:53:11 2010 -0400
@@ -376,6 +376,7 @@
 	lib/libinetsvc \
 	lib/libinetutil \
 	lib/libinstzones \
+	lib/libipadm \
 	lib/libipmi \
 	lib/libipmp \
 	lib/libipp \
--- a/usr/src/Targetdirs	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/Targetdirs	Fri Mar 26 17:53:11 2010 -0400
@@ -118,6 +118,7 @@
 	/etc/hal/fdi/preprobe/10osvendor \
 	/etc/hal/fdi/preprobe/20thirdparty \
 	/etc/hal/fdi/preprobe/30user \
+	/etc/ipadm \
 	/etc/iscsi \
 	/etc/rpcsec	\
 	/etc/security	\
--- a/usr/src/cmd/cmd-inet/lib/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/lib/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -23,12 +23,12 @@
 # Use is subject to license terms.
 #
 
-SUBDIRS=	nwamd netcfgd
-MSGSUBDIRS=	nwamd
+SUBDIRS=	ipmgmtd nwamd netcfgd
+MSGSUBDIRS=	ipmgmtd nwamd
 
-include 	../../Makefile.cmd
+include         ../../Makefile.cmd
 
-POFILES=	$(MSGSUBDIRS:%=%/%.po)
+POFILES=        $(MSGSUBDIRS:%=%/%.po)
 POFILE=		lib.po
 
 all:=		TARGET= all
@@ -46,4 +46,4 @@
 
 FRC:
 
-include		../Makefile.msg
+include         ../Makefile.msg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,90 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+# Needed for ROOTFS_LIBDIR definition
+include		../../../../lib/Makefile.lib
+
+PROG=		ipmgmtd
+OBJS=		ipmgmt_main.o ipmgmt_door.o ipmgmt_persist.o ipmgmt_util.o
+SRCS=		$(OBJS:.o=.c)
+SVCMETHOD=	net-ipmgmt
+MANIFEST=	network-ipmgmt.xml
+CFGFILES=	ipadm.conf
+
+# Needed for ROOTETC definition
+include		../../../Makefile.cmd
+
+POFILE=		$(PROG).po
+POFILES=	ipmgmt_main.po ipmgmt_door.po
+
+ROOTCFGDIR=		$(ROOTETC)/ipadm
+ROOTCFGFILES=		$(CFGFILES:%=$(ROOTCFGDIR)/%)
+ROOTMANIFESTDIR=	$(ROOTSVCNETWORK)
+
+$(ROOTCFGFILES)	:= OWNER= ipadm
+$(ROOTCFGFILES)	:= GROUP= sys
+$(ROOTCFGFILES)	:= FILEMODE= 644
+
+ROOTCMDDIR=	$(ROOTFS_LIBDIR)/inet
+
+LDLIBS += -lipadm -lnvpair -lsecdb -lnsl -lumem
+
+#
+# Instrument ipmgmtd with CTF data to ease debugging.
+#
+CTFCONVERT_HOOK = && $(CTFCONVERT_O)
+CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS)
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+
+.KEEP_STATE:
+
+.PARALLEL:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMERGE_HOOK)
+	$(POST_PROCESS)
+
+install: $(ROOTCMD) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTCFGDIR) \
+	$(ROOTCFGFILES)
+
+check:  $(SRCS) $(HEADERS) $(CHKMANIFEST)
+	$(CSTYLE) -cpP $(SRCS) $(HEADERS)
+
+$(ROOTCMD): $(PROG)
+
+clean:
+	$(RM) $(OBJS)
+
+lint:	lint_SRCS
+
+$(ROOTCFGDIR):
+	$(INS.dir)
+
+$(ROOTCFGDIR)/%: $(ROOTCFGDIR) %
+	$(INS.file)
+
+include 	../../../Makefile.targ
+include		../../Makefile.msg
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# DO NOT EDIT OR PARSE THIS FILE!
+#
+# Use the ipadm(1m) command to change the contents of this file.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,845 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Main door handler functions used by ipmgmtd to process the different door
+ * call requests, issued by the library libipadm.so.
+ */
+
+#include <alloca.h>
+#include <pwd.h>
+#include <auth_attr.h>
+#include <secdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <libnvpair.h>
+#include "ipmgmt_impl.h"
+
+/* Handler declaration for each door command */
+typedef void ipmgmt_door_handler_t(void *argp);
+
+static ipmgmt_door_handler_t	ipmgmt_getaddr_handler,
+				ipmgmt_getprop_handler,
+				ipmgmt_getif_handler,
+				ipmgmt_initif_handler,
+				ipmgmt_aobjop_handler,
+				ipmgmt_resetaddr_handler,
+				ipmgmt_setif_handler,
+				ipmgmt_resetif_handler,
+				ipmgmt_resetprop_handler,
+				ipmgmt_setaddr_handler,
+				ipmgmt_setprop_handler;
+
+typedef struct ipmgmt_door_info_s {
+	uint_t			idi_cmd;
+	boolean_t		idi_set;
+	ipmgmt_door_handler_t	*idi_handler;
+} ipmgmt_door_info_t;
+
+/* maps door commands to door handler functions */
+static ipmgmt_door_info_t i_ipmgmt_door_info_tbl[] = {
+	{ IPMGMT_CMD_SETPROP,		B_TRUE,  ipmgmt_setprop_handler },
+	{ IPMGMT_CMD_SETIF,		B_TRUE,  ipmgmt_setif_handler },
+	{ IPMGMT_CMD_SETADDR,		B_TRUE,  ipmgmt_setaddr_handler },
+	{ IPMGMT_CMD_GETPROP,		B_FALSE, ipmgmt_getprop_handler },
+	{ IPMGMT_CMD_GETIF,		B_FALSE, ipmgmt_getif_handler },
+	{ IPMGMT_CMD_GETADDR,		B_FALSE, ipmgmt_getaddr_handler },
+	{ IPMGMT_CMD_RESETIF,		B_TRUE,  ipmgmt_resetif_handler },
+	{ IPMGMT_CMD_RESETADDR,		B_TRUE,  ipmgmt_resetaddr_handler },
+	{ IPMGMT_CMD_RESETPROP,		B_TRUE,  ipmgmt_resetprop_handler },
+	{ IPMGMT_CMD_INITIF,		B_TRUE,  ipmgmt_initif_handler },
+	{ IPMGMT_CMD_ADDROBJ_LOOKUPADD,	B_TRUE,  ipmgmt_aobjop_handler },
+	{ IPMGMT_CMD_ADDROBJ_ADD,	B_TRUE,  ipmgmt_aobjop_handler },
+	{ IPMGMT_CMD_AOBJNAME2ADDROBJ,	B_FALSE, ipmgmt_aobjop_handler },
+	{ IPMGMT_CMD_LIF2ADDROBJ,	B_FALSE, ipmgmt_aobjop_handler },
+	{ 0, 0, NULL },
+};
+
+/*
+ * The main server procedure function that gets invoked for any of the incoming
+ * door commands. Inside this function we identify the incoming command and
+ * invoke the right door handler function.
+ */
+/* ARGSUSED */
+void
+ipmgmt_handler(void *cookie, char *argp, size_t argsz, door_desc_t *dp,
+    uint_t n_desc)
+{
+	ipmgmt_door_info_t	*infop = NULL;
+	ipmgmt_retval_t		retval;
+	int			i;
+	uint_t			err;
+	ucred_t			*cred = NULL;
+
+	for (i = 0; i_ipmgmt_door_info_tbl[i].idi_cmd != 0; i++) {
+		if (i_ipmgmt_door_info_tbl[i].idi_cmd ==
+		    ((ipmgmt_arg_t *)(void *)argp)->ia_cmd) {
+			infop = &i_ipmgmt_door_info_tbl[i];
+			break;
+		}
+	}
+
+	if (infop == NULL) {
+		ipmgmt_log(LOG_ERR, "Invalid door command specified");
+		err = EINVAL;
+		goto fail;
+	}
+
+	/* check for solaris.network.interface.config authorization */
+	if (infop->idi_set) {
+		uid_t		uid;
+		struct passwd	pwd;
+		char		buf[1024];
+
+		if (door_ucred(&cred) != 0) {
+			err = errno;
+			ipmgmt_log(LOG_ERR, "Could not get user credentials.");
+			goto fail;
+		}
+		uid = ucred_getruid(cred);
+		if ((int)uid < 0) {
+			err = errno;
+			ipmgmt_log(LOG_ERR, "Could not get user id.");
+			goto fail;
+		}
+		if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) ==
+		    NULL) {
+			err = errno;
+			ipmgmt_log(LOG_ERR, "Could not get password entry.");
+			goto fail;
+		}
+		if (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH,
+		    pwd.pw_name) != 1) {
+			err = EPERM;
+			ipmgmt_log(LOG_ERR, "Not authorized for operation.");
+			goto fail;
+		}
+		ucred_free(cred);
+	}
+
+	/* individual handlers take care of calling door_return */
+	infop->idi_handler((void *)argp);
+	return;
+fail:
+	ucred_free(cred);
+	retval.ir_err = err;
+	(void) door_return((char *)&retval, sizeof (retval), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_GETPROP. It retrieves the persisted
+ * property value for the given property.
+ */
+static void
+ipmgmt_getprop_handler(void *argp)
+{
+	ipmgmt_prop_arg_t	*pargp = argp;
+	ipmgmt_getprop_rval_t	rval, *rvalp = &rval;
+
+	assert(pargp->ia_cmd == IPMGMT_CMD_GETPROP);
+
+	rvalp->ir_err = ipmgmt_db_walk(ipmgmt_db_getprop, pargp, IPADM_DB_READ);
+	if (rvalp->ir_err == 0)
+		(void) strlcpy(rvalp->ir_pval, pargp->ia_pval,
+		    sizeof (rvalp->ir_pval));
+	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_SETPROP. It persists the property value
+ * for the given property in the DB.
+ */
+static void
+ipmgmt_setprop_handler(void *argp)
+{
+	ipmgmt_prop_arg_t	*pargp = argp;
+	ipmgmt_retval_t		rval;
+	ipadm_dbwrite_cbarg_t	cb;
+	nvlist_t		*nvl = NULL;
+	int			err;
+
+	assert(pargp->ia_cmd == IPMGMT_CMD_SETPROP);
+
+	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+		goto fail;
+	if (pargp->ia_module[0] != '\0' &&
+	    (err = nvlist_add_string(nvl, IPADM_NVP_PROTONAME,
+	    pargp->ia_module)) != 0) {
+		goto fail;
+	}
+	if (pargp->ia_ifname[0] != '\0' &&
+	    (err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
+	    pargp->ia_ifname)) != 0)
+		goto fail;
+	if (pargp->ia_aobjname[0] != '\0' &&
+	    (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME,
+	    pargp->ia_aobjname)) != 0)
+		goto fail;
+	if ((err = nvlist_add_string(nvl, pargp->ia_pname,
+	    pargp->ia_pval)) != 0)
+		goto fail;
+
+	cb.dbw_nvl = nvl;
+	cb.dbw_flags = pargp->ia_flags;
+	err = ipmgmt_db_walk(ipmgmt_db_update, &cb, IPADM_DB_WRITE);
+fail:
+	nvlist_free(nvl);
+	rval.ir_err = err;
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Helper function for ipmgmt_setaddr_handler().
+ * It converts the nvlist_t, `nvl', to aobjmap node `nodep'.
+ */
+static int
+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;
+
+	/*
+	 * Retrieve all the information needed to build '*nodep' from
+	 * nvlist_t nvl.
+	 */
+	if ((err = nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
+	    &aobjname)) != 0 ||
+	    (err = nvlist_lookup_string(nvl, IPADM_NVP_IFNAME, &ifname)) != 0 ||
+	    (err = nvlist_lookup_int32(nvl, IPADM_NVP_LIFNUM, &lnum)) != 0) {
+		return (err);
+	}
+	if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR)) {
+		af = AF_INET;
+		addrtype = IPADM_ADDR_STATIC;
+	} else if (nvlist_exists(nvl, IPADM_NVP_DHCP)) {
+		af = AF_INET;
+		addrtype = IPADM_ADDR_DHCP;
+	} 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;
+		uint8_t	*addr6;
+		uint32_t plen;
+
+		af = AF_INET6;
+		addrtype = IPADM_ADDR_IPV6_ADDRCONF;
+		if (nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
+		    &plen) != 0)
+			return (EINVAL);
+		if (plen != 0) {
+			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));
+		}
+	}
+
+	/*
+	 * populate the `*nodep' with retrieved values.
+	 */
+	(void) strlcpy(nodep->am_ifname, ifname, sizeof (nodep->am_ifname));
+	(void) strlcpy(nodep->am_aobjname, aobjname,
+	    sizeof (nodep->am_aobjname));
+	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;
+
+	/*
+	 * Do not store logical interface number in persistent store as it
+	 * takes different value on reboot. So remove it from `nvl'.
+	 */
+	if (nvlist_exists(nvl, IPADM_NVP_LIFNUM))
+		(void) nvlist_remove(nvl, IPADM_NVP_LIFNUM, DATA_TYPE_INT32);
+
+	return (0);
+}
+
+/*
+ * 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.
+ */
+static void
+ipmgmt_setaddr_handler(void *argp)
+{
+	ipmgmt_setaddr_arg_t	*sargp = argp;
+	ipmgmt_retval_t		rval;
+	ipmgmt_aobjmap_t	node;
+	nvlist_t		*nvl = NULL;
+	char			*nvlbuf;
+	size_t			nvlsize = sargp->ia_nvlsize;
+	uint32_t		flags = sargp->ia_flags;
+	int			err = 0;
+
+	nvlbuf = (char *)argp + sizeof (ipmgmt_setaddr_arg_t);
+	if ((err = nvlist_unpack(nvlbuf, nvlsize, &nvl, NV_ENCODE_NATIVE)) != 0)
+		goto ret;
+	if (flags & (IPMGMT_ACTIVE|IPMGMT_INIT)) {
+		if ((err = i_ipmgmt_nvl2aobjnode(nvl, &node)) != 0)
+			goto ret;
+		if (flags & IPMGMT_INIT)
+			node.am_flags = (IPMGMT_ACTIVE|IPMGMT_PERSIST);
+		else
+			node.am_flags = flags;
+		if ((err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD)) != 0)
+			goto ret;
+	}
+	if (flags & IPMGMT_PERSIST) {
+		ipadm_dbwrite_cbarg_t	cb;
+
+		cb.dbw_nvl = nvl;
+		cb.dbw_flags = 0;
+		err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
+	}
+ret:
+	nvlist_free(nvl);
+	rval.ir_err = err;
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Handles the door commands that 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
+ *	generates an `aobjname' for address object for the library to use.
+ * IPMGMT_CMD_ADDROBJ_ADD - add/update address object in `aobjmap'
+ * IPMGMT_CMD_LIF2ADDROBJ - given a logical interface, return address object
+ *	associated with that logical interface.
+ * IPMGMT_CMD_AOBJNAME2ADDROBJ - given an address object name return logical
+ *	interface associated with that address object.
+ */
+static void
+ipmgmt_aobjop_handler(void *argp)
+{
+	ipmgmt_aobjop_arg_t	*largp = argp;
+	ipmgmt_retval_t		rval;
+	ipmgmt_aobjop_rval_t	aobjrval;
+	void			*rvalp;
+	size_t			rsize;
+	ipmgmt_aobjmap_t	node;
+	int			err = 0;
+	char			*ifname = largp->ia_ifname;
+	char			*aobjname = largp->ia_aobjname;
+	int32_t			lnum = largp->ia_lnum;
+	sa_family_t		af = largp->ia_family;
+	ipadm_addr_type_t	atype = largp->ia_atype;
+	ipmgmt_aobjmap_t	*head;
+
+	switch (largp->ia_cmd) {
+	case IPMGMT_CMD_ADDROBJ_LOOKUPADD:
+		rsize = sizeof (ipmgmt_aobjop_rval_t);
+		rvalp = &aobjrval;
+		bzero(&node, sizeof (node));
+		(void) strlcpy(node.am_aobjname, aobjname,
+		    sizeof (node.am_aobjname));
+		(void) strlcpy(node.am_ifname, ifname,
+		    sizeof (node.am_ifname));
+		node.am_family = af;
+		/* no logical number is associated with this addrobj yet */
+		node.am_lnum = -1;
+		/* The address object is not persisted yet. */
+		node.am_flags = IPMGMT_ACTIVE;
+		err = ipmgmt_aobjmap_op(&node, ADDROBJ_LOOKUPADD);
+		if (err == 0) {
+			(void) strlcpy(aobjrval.ir_aobjname, node.am_aobjname,
+			    sizeof (aobjrval.ir_aobjname));
+		}
+		break;
+	case IPMGMT_CMD_ADDROBJ_ADD:
+		rsize = sizeof (ipmgmt_retval_t);
+		rvalp = &rval;
+		if (aobjname[0] == '\0' || ifname[0] == '\0' || lnum == -1 ||
+		    af == AF_UNSPEC) {
+			err = EINVAL;
+			break;
+		}
+		bzero(&node, sizeof (node));
+		(void) strlcpy(node.am_aobjname, aobjname,
+		    sizeof (node.am_aobjname));
+		(void) strlcpy(node.am_ifname, ifname,
+		    sizeof (node.am_ifname));
+		node.am_atype = atype;
+		node.am_lnum = lnum;
+		node.am_family = af;
+		/* The address object is not persisted. */
+		node.am_flags = IPMGMT_ACTIVE;
+		err = ipmgmt_aobjmap_op(&node, ADDROBJ_ADD);
+		break;
+	case IPMGMT_CMD_AOBJNAME2ADDROBJ:
+		rsize = sizeof (ipmgmt_aobjop_rval_t);
+		rvalp = &aobjrval;
+		bzero(&aobjrval, sizeof (aobjrval));
+		if (aobjname[0] == '\0') {
+			err = EINVAL;
+			break;
+		}
+		(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
+		head = aobjmap.aobjmap_head;
+		for (; head; head = head->am_next) {
+			if (strcmp(head->am_aobjname, aobjname) != 0)
+				continue;
+			/*
+			 * For an auto-configured interface, return
+			 * the lifnum that has the link-local on it.
+			 * Other logical interfaces were created for
+			 * prefixes and dhcpv6 addresses and do not
+			 * have am_ifid set.
+			 */
+			if (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
+			    head->am_linklocal) {
+				break;
+			}
+		}
+		if (head == NULL) {
+			err = ENOENT;
+			(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+			break;
+		}
+		(void) strlcpy(aobjrval.ir_ifname, head->am_ifname,
+		    sizeof (aobjrval.ir_ifname));
+		aobjrval.ir_lnum = head->am_lnum;
+		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;
+		(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+		break;
+	case IPMGMT_CMD_LIF2ADDROBJ:
+		rsize = sizeof (ipmgmt_aobjop_rval_t);
+		rvalp = &aobjrval;
+		bzero(&aobjrval, sizeof (aobjrval));
+		if (ifname[0] == '\0') {
+			err = EINVAL;
+			break;
+		}
+		(void) pthread_rwlock_rdlock(&aobjmap.aobjmap_rwlock);
+		head = aobjmap.aobjmap_head;
+		for (; head; head = head->am_next) {
+			if (strcmp(head->am_ifname, ifname) == 0 &&
+			    head->am_lnum == lnum &&
+			    head->am_family == af) {
+				break;
+			}
+		}
+		if (head == NULL) {
+			err = ENOENT;
+			(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+			break;
+		}
+		(void) strlcpy(aobjrval.ir_aobjname, head->am_aobjname,
+		    sizeof (aobjrval.ir_aobjname));
+		aobjrval.ir_atype = head->am_atype;
+		aobjrval.ir_flags = head->am_flags;
+		(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+		break;
+	default:
+		rsize = sizeof (ipmgmt_retval_t);
+		rvalp = &rval;
+		err = EINVAL;
+	}
+	((ipmgmt_retval_t *)rvalp)->ir_err = err;
+	(void) door_return((char *)rvalp, rsize, NULL, 0);
+}
+
+/*
+ * Given an interface name and family, deletes all the address objects
+ * associated with it.
+ */
+void
+i_ipmgmt_delif_aobjs(char *ifname, sa_family_t af, uint32_t flags)
+{
+	ipmgmt_aobjmap_t	*head, *next, *prev;
+	ipadm_db_op_t		db_op;
+
+	prev = NULL;
+
+	(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
+	head = aobjmap.aobjmap_head;
+	for (; head; head = next) {
+		next = head->am_next;
+		if (strcmp(head->am_ifname, ifname) != 0 ||
+		    head->am_family != af) {
+			prev = head;
+			continue;
+		}
+
+		if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
+		    flags == IPMGMT_ACTIVE) {
+			/*
+			 * If the addres is present in both active and
+			 * persistent store, and if we are performing
+			 * a temporary delete, we update the node to
+			 * indicate that the address is only present in
+			 * persistent store and we proceed. Otherwise
+			 * we always delete the node from aobjmap.
+			 */
+			head->am_flags &= ~IPMGMT_ACTIVE;
+			head->am_lnum = -1;
+			db_op = IPADM_DB_WRITE;
+		} else {
+			db_op = IPADM_DB_DELETE;
+			if (prev == NULL)
+				aobjmap.aobjmap_head = next;
+			else
+				prev->am_next = next;
+		}
+		(void) ipmgmt_persist_aobjmap(head, db_op);
+		if (db_op == IPADM_DB_DELETE)
+			free(head);
+	}
+	(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_SETIF. It persists the interface
+ * information in the DB.
+ */
+static void
+ipmgmt_setif_handler(void *argp)
+{
+	ipmgmt_if_arg_t		*sargp = argp;
+	ipmgmt_retval_t		rval;
+	ipadm_dbwrite_cbarg_t	cb;
+	uint32_t		flags = sargp->ia_flags;
+	nvlist_t		*nvl = NULL;
+	int			err = 0;
+	char			strval[IPMGMT_STRSIZE];
+
+	if (!(flags & IPMGMT_PERSIST) || sargp->ia_family == AF_UNSPEC ||
+	    sargp->ia_ifname[0] == '\0') {
+		err = EINVAL;
+		goto ret;
+	}
+	if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0)
+		goto ret;
+	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
+	    sargp->ia_ifname)) != 0)
+		goto ret;
+	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", sargp->ia_family);
+	if ((err = nvlist_add_string(nvl, IPADM_NVP_FAMILY, strval)) != 0)
+		goto ret;
+	cb.dbw_nvl = nvl;
+	cb.dbw_flags = 0;
+	err = ipmgmt_db_walk(ipmgmt_db_add, &cb, IPADM_DB_WRITE);
+ret:
+	rval.ir_err = err;
+	nvlist_free(nvl);
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_RESETIF. For the given interface,
+ * deletes all the persisted interface configuration. It also deletes, from
+ * `aobjmap', all the address objects configured on the given interface.
+ */
+static void
+ipmgmt_resetif_handler(void *argp)
+{
+	ipmgmt_if_arg_t		*rargp = argp;
+	ipmgmt_retval_t		rval;
+	ipmgmt_if_cbarg_t	cbarg;
+	uint32_t		flags = rargp->ia_flags;
+	int			err = 0;
+
+	cbarg.cb_family = rargp->ia_family;
+	cbarg.cb_ifname = rargp->ia_ifname;
+	if (flags & IPMGMT_PERSIST)
+		err = ipmgmt_db_walk(ipmgmt_db_resetif, &cbarg,
+		    IPADM_DB_DELETE);
+
+	if (flags & IPMGMT_ACTIVE)
+		i_ipmgmt_delif_aobjs(rargp->ia_ifname, rargp->ia_family,
+		    flags);
+
+	rval.ir_err = err;
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_RESETADDR. For the given addrobj
+ * deletes all the persisted addrobj configuration. It also deletes the
+ * corresponding node, from `aobjmap'.
+ */
+static void
+ipmgmt_resetaddr_handler(void *argp)
+{
+	ipmgmt_addr_arg_t	*rargp = argp;
+	ipmgmt_retval_t		rval;
+	ipmgmt_aobjmap_t	node;
+	uint32_t		flags = rargp->ia_flags;
+	int			err = 0;
+	ipmgmt_resetaddr_cbarg_t cbarg;
+
+	cbarg.cb_aobjname = rargp->ia_aobjname;
+
+	if (flags & IPMGMT_PERSIST)
+		err = ipmgmt_db_walk(ipmgmt_db_resetaddr, &cbarg,
+		    IPADM_DB_DELETE);
+
+	if (flags & IPMGMT_ACTIVE) {
+		bzero(&node, sizeof (node));
+		(void) strlcpy(node.am_aobjname, rargp->ia_aobjname,
+		    sizeof (node.am_aobjname));
+
+		/*
+		 * am_lnum is used only for IPv6 autoconf case, since there
+		 * can be multiple nodes with the same aobjname.
+		 */
+		node.am_lnum = rargp->ia_lnum;
+		node.am_flags = flags;
+		(void) ipmgmt_aobjmap_op(&node, ADDROBJ_DELETE);
+	}
+
+	rval.ir_err = err;
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_GETADDR. It retrieves the persisted
+ * address for a given `gargp->ia_aobjname'. If it is not defined then it
+ * retrieves all the addresses configured on `gargp->ia_ifname'. The
+ * "ipadm show-addr addrobj" or "ipadm show-addr <ifname>/\*" will call this
+ * handler through library.
+ */
+static void
+ipmgmt_getaddr_handler(void *argp)
+{
+	size_t			buflen, onvlsize;
+	char			*buf, *onvlbuf;
+	ipmgmt_getaddr_arg_t	*gargp = argp;
+	ipmgmt_getaddr_cbarg_t	cbarg;
+	ipmgmt_get_rval_t 	rval, *rvalp = &rval;
+	int			err = 0;
+
+	cbarg.cb_ifname = gargp->ia_ifname;
+	cbarg.cb_aobjname = gargp->ia_aobjname;
+	cbarg.cb_ocnt = 0;
+	if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
+		goto fail;
+	err = ipmgmt_db_walk(ipmgmt_db_getaddr, &cbarg, IPADM_DB_READ);
+	if (err == ENOENT && cbarg.cb_ocnt > 0) {
+		/*
+		 * If there is atleast one entry in the nvlist,
+		 * do not return error.
+		 */
+		err = 0;
+	}
+	if (err != 0)
+		goto fail;
+
+	if ((err = nvlist_size(cbarg.cb_onvl, &onvlsize,
+	    NV_ENCODE_NATIVE)) != 0) {
+		goto fail;
+	}
+	buflen = onvlsize + sizeof (ipmgmt_get_rval_t);
+	/*
+	 * We cannot use malloc() here because door_return never returns, and
+	 * memory allocated by malloc() would get leaked. Use alloca() instead.
+	 */
+	buf = alloca(buflen);
+	onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
+	if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &onvlsize,
+	    NV_ENCODE_NATIVE, 0)) != 0) {
+		goto fail;
+	}
+	nvlist_free(cbarg.cb_onvl);
+	rvalp = (ipmgmt_get_rval_t *)(void *)buf;
+	rvalp->ir_err = 0;
+	rvalp->ir_nvlsize = onvlsize;
+
+	(void) door_return(buf, buflen, NULL, 0);
+	return;
+fail:
+	nvlist_free(cbarg.cb_onvl);
+	rvalp->ir_err = err;
+	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_RESETPROP. It deletes the property line
+ * from the DB.
+ */
+static void
+ipmgmt_resetprop_handler(void *argp)
+{
+	ipmgmt_prop_arg_t	*pargp = argp;
+	ipmgmt_retval_t		rval;
+
+	assert(pargp->ia_cmd == IPMGMT_CMD_RESETPROP);
+
+	rval.ir_err = ipmgmt_db_walk(ipmgmt_db_resetprop, pargp,
+	    IPADM_DB_DELETE);
+	(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_GETIF. It retrieves the name of all the
+ * persisted interfaces and the IP protocols (IPv4 or IPv6) they support.
+ */
+static void
+ipmgmt_getif_handler(void *argp)
+{
+	ipmgmt_getif_arg_t	*getif = argp;
+	ipmgmt_getif_rval_t	*rvalp;
+	ipmgmt_retval_t		rval;
+	ipmgmt_getif_cbarg_t	cbarg;
+	ipadm_if_info_t		*ifp, *rifp, *curifp;
+	int			i, err = 0, count = 0;
+	size_t			rbufsize;
+
+	assert(getif->ia_cmd == IPMGMT_CMD_GETIF);
+
+	bzero(&cbarg, sizeof (cbarg));
+	cbarg.cb_ifname = getif->ia_ifname;
+	err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
+	if (err == ENOENT && cbarg.cb_ifinfo) {
+		/*
+		 * If there is atleast one entry in the nvlist,
+		 * do not return error.
+		 */
+		err = 0;
+	}
+	if (err != 0) {
+		rval.ir_err = err;
+		(void) door_return((char *)&rval, sizeof (rval), NULL, 0);
+		return;
+	}
+
+	/* allocate sufficient buffer to return the interface info */
+	for (ifp = cbarg.cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next)
+		++count;
+	rbufsize = sizeof (*rvalp) + count * sizeof (*ifp);
+	rvalp = alloca(rbufsize);
+	bzero(rvalp, rbufsize);
+
+	rvalp->ir_ifcnt = count;
+	rifp = rvalp->ir_ifinfo;
+	ifp = cbarg.cb_ifinfo;
+
+	/*
+	 * copy the interface info to buffer allocated on stack. The reason
+	 * we do this is to avoid memory leak, as door_return() would never
+	 * return
+	 */
+	for (i = 0; i < count; i++) {
+		rifp = rvalp->ir_ifinfo + i;
+		(void) bcopy(ifp, rifp, sizeof (*rifp));
+		rifp->ifi_next = NULL;
+		curifp = ifp->ifi_next;
+		free(ifp);
+		ifp = curifp;
+	}
+	rvalp->ir_err = err;
+	(void) door_return((char *)rvalp, rbufsize, NULL, 0);
+}
+
+/*
+ * Handles the door command IPMGMT_CMD_INITIF. It retrieves all the persisted
+ * interface configuration (interface properties and addresses), for all those
+ * interfaces that need to be initialized.
+ */
+static void
+ipmgmt_initif_handler(void *argp)
+{
+	ipmgmt_initif_arg_t	*initif = argp;
+	size_t			buflen, nvlsize;
+	char			*buf = NULL, *onvlbuf, *invlbuf;
+	ipmgmt_get_rval_t	rval, *rvalp = &rval;
+	ipmgmt_initif_cbarg_t	cbarg;
+	int			err;
+
+	assert(initif->ia_cmd == IPMGMT_CMD_INITIF);
+
+	bzero(&cbarg, sizeof (cbarg));
+	invlbuf = (char *)argp + sizeof (ipmgmt_initif_arg_t);
+	nvlsize = initif->ia_nvlsize;
+	err = nvlist_unpack(invlbuf, nvlsize, &cbarg.cb_invl, NV_ENCODE_NATIVE);
+	if (err != 0)
+		goto fail;
+
+	cbarg.cb_family = initif->ia_family;
+	if (nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0) != 0)
+		goto fail;
+
+	err = ipmgmt_db_walk(ipmgmt_db_initif, &cbarg, IPADM_DB_READ);
+	if (err == ENOENT && cbarg.cb_ocnt > 0) {
+		/*
+		 * If there is atleast one entry in the nvlist,
+		 * do not return error.
+		 */
+		err = 0;
+	}
+	if (err != 0)
+		goto fail;
+
+	if ((err = nvlist_size(cbarg.cb_onvl, &nvlsize, NV_ENCODE_NATIVE)) != 0)
+		goto fail;
+	buflen = nvlsize + sizeof (ipmgmt_get_rval_t);
+	/*
+	 * We cannot use malloc() here because door_return never returns, and
+	 * memory allocated by malloc() would get leaked. Use alloca() instead.
+	 */
+	buf = alloca(buflen);
+	onvlbuf = buf + sizeof (ipmgmt_get_rval_t);
+	if ((err = nvlist_pack(cbarg.cb_onvl, &onvlbuf, &nvlsize,
+	    NV_ENCODE_NATIVE, 0)) != 0) {
+		goto fail;
+	}
+	nvlist_free(cbarg.cb_invl);
+	nvlist_free(cbarg.cb_onvl);
+	rvalp = (ipmgmt_get_rval_t *)(void *)buf;
+	rvalp->ir_err = 0;
+	rvalp->ir_nvlsize = nvlsize;
+
+	(void) door_return(buf, buflen, NULL, 0);
+	return;
+fail:
+	nvlist_free(cbarg.cb_invl);
+	nvlist_free(cbarg.cb_onvl);
+	rvalp->ir_err = err;
+	(void) door_return((char *)rvalp, sizeof (*rvalp), NULL, 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,152 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_IPMGMT_IMPL_H
+#define	_IPMGMT_IMPL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <net/if.h>
+#include <libnvpair.h>
+#include <libipadm.h>
+#include <ipadm_ipmgmt.h>
+#include <syslog.h>
+#include <pthread.h>
+
+#define	IPMGMT_STRSIZE		256
+
+/* ipmgmt_door.c */
+extern void	ipmgmt_handler(void *, char *, size_t, door_desc_t *, uint_t);
+
+/* ipmgmt_util.c */
+extern void	ipmgmt_log(int, const char *, ...);
+
+/* ipmgmt_persist.c */
+
+/*
+ * following are the list of DB walker callback functions and the callback
+ * arguments for each of the callback functions used by the daemon
+ */
+/* following functions take 'ipmgmt_prop_arg_t' as the callback argument */
+extern db_wfunc_t	ipmgmt_db_getprop, ipmgmt_db_resetprop;
+
+/* following functions take ipadm_dbwrite_cbarg_t as callback argument */
+extern db_wfunc_t	ipmgmt_db_add, ipmgmt_db_update;
+
+typedef struct {
+	char		*cb_ifname;
+	ipadm_if_info_t	*cb_ifinfo;
+} ipmgmt_getif_cbarg_t;
+extern db_wfunc_t	ipmgmt_db_getif;
+
+typedef struct {
+	char		*cb_aobjname;
+	char		*cb_ifname;
+	nvlist_t	*cb_onvl;
+	int		cb_ocnt;
+} ipmgmt_getaddr_cbarg_t;
+extern db_wfunc_t	ipmgmt_db_getaddr;
+
+typedef struct {
+	sa_family_t	cb_family;
+	char		*cb_ifname;
+} ipmgmt_if_cbarg_t;
+extern db_wfunc_t	ipmgmt_db_setif, ipmgmt_db_resetif;
+
+typedef struct {
+	char		*cb_aobjname;
+} ipmgmt_resetaddr_cbarg_t;
+extern db_wfunc_t	ipmgmt_db_resetaddr;
+
+typedef struct {
+	sa_family_t	cb_family;
+	nvlist_t	*cb_invl;
+	nvlist_t	*cb_onvl;
+	int		cb_ocnt;
+} ipmgmt_initif_cbarg_t;
+extern db_wfunc_t	ipmgmt_db_initif;
+
+/*
+ * A linked list of address object nodes. Each node in the list tracks
+ * following information for the address object identified by `am_aobjname'.
+ *	- interface on which the address is created
+ * 	- logical interface number on which the address is created
+ *	- address family
+ *	- `am_nextnum' identifies the next number to use to generate user part
+ *	  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
+ */
+typedef struct ipmgmt_aobjmap_s {
+	struct ipmgmt_aobjmap_s	*am_next;
+	char			am_aobjname[IPADM_AOBJSIZ];
+	char			am_ifname[LIFNAMSIZ];
+	int32_t			am_lnum;
+	sa_family_t		am_family;
+	ipadm_addr_type_t	am_atype;
+	uint32_t		am_nextnum;
+	uint32_t		am_flags;
+	boolean_t		am_linklocal;
+	struct sockaddr_storage	am_ifid;
+} ipmgmt_aobjmap_t;
+
+/* linked list of `aobjmap' nodes, protected by RW lock */
+typedef struct ipmgmt_aobjmap_list_s {
+	ipmgmt_aobjmap_t	*aobjmap_head;
+	pthread_rwlock_t	aobjmap_rwlock;
+} ipmgmt_aobjmap_list_t;
+
+/* global `aobjmap' defined in ipmgmt_main.c */
+extern ipmgmt_aobjmap_list_t aobjmap;
+
+/* operations on the `aobjmap' linked list */
+#define	ADDROBJ_ADD		0x00000001
+#define	ADDROBJ_DELETE		0x00000002
+#define	ADDROBJ_LOOKUPADD	0x00000004
+
+/*
+ * A temporary file created in SMF volatile filesystem. This file captures the
+ * in-memory copy of list `aobjmap' on disk. This is done to recover from
+ * daemon reboot (using svcadm) or crashes.
+ */
+#define	ADDROBJ_MAPPING_DB_FILE	IPADM_TMPFS_DIR"/aobjmap.conf"
+
+extern int		ipmgmt_db_walk(db_wfunc_t *, void *, ipadm_db_op_t);
+extern int		ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *, uint32_t);
+extern boolean_t	ipmgmt_aobjmap_init(void *, nvlist_t *, char *,
+			    size_t, int *);
+extern int 		ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *,
+			    ipadm_db_op_t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _IPMGMT_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,382 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The ipmgmtd daemon is started by ip-interface-management SMF service. This
+ * daemon is used to manage, mapping of 'address object' to 'interface name' and
+ * 'logical interface number', on which the address is created. It also provides
+ * a means to update the ipadm persistent data-store.
+ *
+ * The daemon tracks the <addrobj, lifname> mapping in-memory using a linked
+ * list `aobjmap'. Access to this list is synchronized using a readers-writers
+ * lock. The active <addrobj, lifname> mapping is kept in
+ * /etc/svc/volatile/ipadm/aobjmap.conf cache file, so that the mapping can be
+ * recovered when ipmgmtd exits for some reason (e.g., when ipmgmtd is restarted
+ * using svcadm or accidentally killed).
+ *
+ * Today, the persistent configuration of interfaces, addresses and protocol
+ * properties is kept in /etc/ipadm/ipadm.conf. The access to the persistent
+ * data store is synchronized using reader-writers lock `ipmgmt_dbconf_lock'.
+ *
+ * The communication between the library, libipadm.so and the daemon, is through
+ * doors RPC. The library interacts with the daemon using the commands defined
+ * by `ipmgmt_door_cmd_type_t'. Further any 'write' operation would require
+ * the `NETWORK_INTERFACE_CONFIG_AUTH' authorization.
+ *
+ * On reboot, the aforementioned SMF service starts the daemon before any other
+ * networking service that configures network IP interfaces is started.
+ * Afterwards, the network/physical SMF script instantiates the persisted
+ * network interfaces, interface properties and addresses.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <priv_utils.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "ipmgmt_impl.h"
+
+const char		*progname;
+
+/* readers-writers lock for reading/writing daemon data store */
+pthread_rwlock_t	ipmgmt_dbconf_lock;
+
+/* tracks address object to {ifname|logical number|interface id} mapping */
+ipmgmt_aobjmap_list_t	aobjmap;
+
+/* used to communicate failure to parent process, which spawned the daemon */
+static int		pfds[2];
+
+/* file descriptor to IPMGMT_DOOR */
+static int		ipmgmt_door_fd = -1;
+
+static void		ipmgmt_exit(int);
+static int		ipmgmt_init();
+static int		ipmgmt_init_privileges();
+
+static int
+ipmgmt_db_init()
+{
+	int		fd, err;
+
+	/* creates the address object data store, if it doesn't exist */
+	if ((fd = open(ADDROBJ_MAPPING_DB_FILE, O_CREAT|O_RDONLY,
+	    IPADM_FILE_MODE)) == -1) {
+		err = errno;
+		ipmgmt_log(LOG_ERR, "could not open %s: %s",
+		    ADDROBJ_MAPPING_DB_FILE, strerror(err));
+		return (err);
+	}
+	(void) close(fd);
+
+	aobjmap.aobjmap_head = NULL;
+	(void) pthread_rwlock_init(&aobjmap.aobjmap_rwlock, NULL);
+
+	/*
+	 * If the daemon is recovering from a crash or restart, read the
+	 * address object to logical interface mapping and build an in-memory
+	 * representation of the mapping. That is, build `aobjmap' structure
+	 * from address object data store.
+	 */
+	if ((err = ipadm_rw_db(ipmgmt_aobjmap_init, NULL,
+	    ADDROBJ_MAPPING_DB_FILE, 0, IPADM_DB_READ)) != 0) {
+		/* if there was nothing to initialize, it's fine */
+		if (err != ENOENT)
+			return (err);
+		err = 0;
+	}
+
+	(void) pthread_rwlock_init(&ipmgmt_dbconf_lock, NULL);
+	return (err);
+}
+
+static int
+ipmgmt_door_init()
+{
+	int fd;
+	int err;
+
+	/* create the door file for ipmgmtd */
+	if ((fd = open(IPMGMT_DOOR, O_CREAT|O_RDONLY, IPADM_FILE_MODE)) == -1) {
+		err = errno;
+		ipmgmt_log(LOG_ERR, "could not open %s: %s",
+		    IPMGMT_DOOR, strerror(err));
+		return (err);
+	}
+	(void) close(fd);
+
+	if ((ipmgmt_door_fd = door_create(ipmgmt_handler, NULL,
+	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+		err = errno;
+		ipmgmt_log(LOG_ERR, "failed to create door: %s", strerror(err));
+		return (err);
+	}
+	/*
+	 * fdetach first in case a previous daemon instance exited
+	 * ungracefully.
+	 */
+	(void) fdetach(IPMGMT_DOOR);
+	if (fattach(ipmgmt_door_fd, IPMGMT_DOOR) != 0) {
+		err = errno;
+		ipmgmt_log(LOG_ERR, "failed to attach door to %s: %s",
+		    IPMGMT_DOOR, strerror(err));
+		goto fail;
+	}
+	return (0);
+fail:
+	(void) door_revoke(ipmgmt_door_fd);
+	ipmgmt_door_fd = -1;
+	return (err);
+}
+
+static void
+ipmgmt_door_fini()
+{
+	if (ipmgmt_door_fd == -1)
+		return;
+
+	(void) fdetach(IPMGMT_DOOR);
+	if (door_revoke(ipmgmt_door_fd) == -1) {
+		ipmgmt_log(LOG_ERR, "failed to revoke access to door %s: %s",
+		    IPMGMT_DOOR, strerror(errno));
+	}
+}
+
+static int
+ipmgmt_init()
+{
+	int err;
+
+	if (signal(SIGTERM, ipmgmt_exit) == SIG_ERR ||
+	    signal(SIGINT, ipmgmt_exit) == SIG_ERR) {
+		err = errno;
+		ipmgmt_log(LOG_ERR, "signal() for SIGTERM/INT failed: %s",
+		    strerror(err));
+		return (err);
+	}
+	if ((err = ipmgmt_db_init()) != 0 || (err = ipmgmt_door_init()) != 0)
+		return (err);
+	return (0);
+}
+
+/*
+ * This is called by the child process to inform the parent process to
+ * exit with the given return value.
+ */
+static void
+ipmgmt_inform_parent_exit(int rv)
+{
+	if (write(pfds[1], &rv, sizeof (int)) != sizeof (int)) {
+		ipmgmt_log(LOG_WARNING,
+		    "failed to inform parent process of status: %s",
+		    strerror(errno));
+		(void) close(pfds[1]);
+		exit(EXIT_FAILURE);
+	}
+	(void) close(pfds[1]);
+}
+
+/*ARGSUSED*/
+static void
+ipmgmt_exit(int signo)
+{
+	(void) close(pfds[1]);
+	ipmgmt_door_fini();
+	exit(EXIT_FAILURE);
+}
+
+/*
+ * Set the uid of this daemon to the "ipadm" user. Finish the following
+ * operations before setuid() because they need root privileges:
+ *
+ *    - create the /etc/svc/volatile/ipadm directory;
+ *    - change its uid/gid to "ipadm"/"sys";
+ */
+static int
+ipmgmt_init_privileges()
+{
+	struct stat	statbuf;
+	int err;
+
+	/* create the IPADM_TMPFS_DIR directory */
+	if (stat(IPADM_TMPFS_DIR, &statbuf) < 0) {
+		if (mkdir(IPADM_TMPFS_DIR, (mode_t)0755) < 0) {
+			err = errno;
+			goto fail;
+		}
+	} else {
+		if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
+			err = ENOTDIR;
+			goto fail;
+		}
+	}
+
+	if ((chmod(IPADM_TMPFS_DIR, 0755) < 0) ||
+	    (chown(IPADM_TMPFS_DIR, UID_NETADM, GID_NETADM) < 0)) {
+		err = errno;
+		goto fail;
+	}
+
+	/*
+	 * limit the privileges of this daemon and set the uid of this
+	 * daemon to UID_NETADM
+	 */
+	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, UID_NETADM,
+	    GID_NETADM, NULL) == -1) {
+		err = EPERM;
+		goto fail;
+	}
+
+	return (0);
+fail:
+	(void) ipmgmt_log(LOG_ERR, "failed to initialize the daemon: %s",
+	    strerror(err));
+	return (err);
+}
+
+/*
+ * Keep the pfds fd open, close other fds.
+ */
+/*ARGSUSED*/
+static int
+closefunc(void *arg, int fd)
+{
+	if (fd != pfds[1])
+		(void) close(fd);
+	return (0);
+}
+
+/*
+ * We cannot use libc's daemon() because the door we create is associated with
+ * the process ID. If we create the door before the call to daemon(), it will
+ * be associated with the parent and it's incorrect. On the other hand if we
+ * create the door later, after the call to daemon(), parent process exits
+ * early and gives a false notion to SMF that 'ipmgmtd' is up and running,
+ * which is incorrect. So, we have our own daemon() equivalent.
+ */
+static boolean_t
+ipmgmt_daemonize(void)
+{
+	pid_t pid;
+	int rv;
+
+	if (pipe(pfds) < 0) {
+		(void) fprintf(stderr, "%s: pipe() failed: %s\n",
+		    progname, strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+
+	if ((pid = fork()) == -1) {
+		(void) fprintf(stderr, "%s: fork() failed: %s\n",
+		    progname, strerror(errno));
+		exit(EXIT_FAILURE);
+	} else if (pid > 0) { /* Parent */
+		(void) close(pfds[1]);
+
+		/*
+		 * Parent should not exit early, it should wait for the child
+		 * to return Success/Failure. If the parent exits early, then
+		 * SMF will think 'ipmgmtd' is up and would start all the
+		 * depended services.
+		 *
+		 * If the child process exits unexpectedly, read() returns -1.
+		 */
+		if (read(pfds[0], &rv, sizeof (int)) != sizeof (int)) {
+			(void) kill(pid, SIGKILL);
+			rv = EXIT_FAILURE;
+		}
+
+		(void) close(pfds[0]);
+		exit(rv);
+	}
+
+	/* Child */
+	(void) close(pfds[0]);
+	(void) setsid();
+
+	/* close all files except pfds[1] */
+	(void) fdwalk(closefunc, NULL);
+	(void) chdir("/");
+	openlog(progname, LOG_PID, LOG_DAEMON);
+	return (B_TRUE);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int opt;
+	boolean_t fg = B_FALSE;
+
+	progname = strrchr(argv[0], '/');
+	if (progname != NULL)
+		progname++;
+	else
+		progname = argv[0];
+
+	/* Process options */
+	while ((opt = getopt(argc, argv, "f")) != EOF) {
+		switch (opt) {
+		case 'f':
+			fg = B_TRUE;
+			break;
+		default:
+			(void) fprintf(stderr, "Usage: %s [-f]\n", progname);
+			return (EXIT_FAILURE);
+		}
+	}
+
+	if (!fg && getenv("SMF_FMRI") == NULL) {
+		(void) fprintf(stderr,
+		    "ipmgmtd is a smf(5) managed service and cannot be run "
+		    "from the command line.\n");
+		return (EINVAL);
+	}
+
+	if (!fg && !ipmgmt_daemonize())
+		return (EXIT_FAILURE);
+
+	if (ipmgmt_init_privileges() != 0)
+		goto child_out;
+
+	if (ipmgmt_init() != 0)
+		goto child_out;
+
+	/* Inform the parent process that it can successfully exit */
+	ipmgmt_inform_parent_exit(EXIT_SUCCESS);
+
+	for (;;)
+		(void) pause();
+
+child_out:
+	/* return from main() forcibly exits an MT process */
+	ipmgmt_inform_parent_exit(EXIT_FAILURE);
+	return (EXIT_FAILURE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,1136 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Contains DB walker functions, which are of type `db_wfunc_t';
+ *
+ * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
+ *				size_t bufsize, int *errp);
+ *
+ * ipadm_rw_db() walks through the data store, one line at a time and calls
+ * these call back functions with:
+ *	`cbarg'  - callback argument
+ *	`db_nvl' - representing a line from DB in nvlist_t form
+ *	`buf'	 - character buffer to hold modified line
+ *	`bufsize'- size of the buffer
+ *	`errp' - captures any error inside the walker function.
+ *
+ * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
+ * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
+ * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
+ * the modified `buf' is written back into DB.
+ *
+ * All the 'read' callback functions, retrieve the information from the DB, by
+ * reading `db_nvl' and then populate the `cbarg'.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include "ipmgmt_impl.h"
+
+#define	ATYPE	"_atype"		/* name of the address type nvpair */
+#define	FLAGS	"_flags"		/* name of the flags nvpair */
+
+/*
+ * flag used by ipmgmt_persist_aobjmap() to indicate address type is
+ * IPADM_ADDR_IPV6_ADDRCONF.
+ */
+#define	IPMGMT_ATYPE_V6ACONF	0x1
+
+extern pthread_rwlock_t ipmgmt_dbconf_lock;
+
+/*
+ * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
+ * in private nvpairs `proto', `ifname' & `aobjname'.
+ */
+static boolean_t
+ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
+    const char *aobjname)
+{
+	char		*db_proto = NULL, *db_ifname = NULL;
+	char		*db_aobjname = NULL;
+	nvpair_t	*nvp;
+	char		*name;
+
+	/* walk through db_nvl and retrieve all its private nvpairs */
+	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_proto);
+		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_ifname);
+		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_aobjname);
+	}
+
+	if (proto != NULL && proto[0] == '\0')
+		proto = NULL;
+	if (ifname != NULL && ifname[0] == '\0')
+		ifname = NULL;
+	if (aobjname != NULL && aobjname[0] == '\0')
+		aobjname = NULL;
+
+	if ((proto == NULL && db_proto != NULL) ||
+	    (proto != NULL && db_proto == NULL) ||
+	    strcmp(proto, db_proto) != 0) {
+		/* no intersection - different protocols. */
+		return (B_FALSE);
+	}
+	if ((ifname == NULL && db_ifname != NULL) ||
+	    (ifname != NULL && db_ifname == NULL) ||
+	    strcmp(ifname, db_ifname) != 0) {
+		/* no intersection - different interfaces. */
+		return (B_FALSE);
+	}
+	if ((aobjname == NULL && db_aobjname != NULL) ||
+	    (aobjname != NULL && db_aobjname == NULL) ||
+	    strcmp(aobjname, db_aobjname) != 0) {
+		/* no intersection - different address objects */
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
+ */
+static boolean_t
+ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
+{
+	nvpair_t	*nvp;
+	char		*name;
+	char		*proto = NULL, *ifname = NULL, *aobjname = NULL;
+
+	/* walk through in_nvl and retrieve all its private nvpairs */
+	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
+			(void) nvpair_value_string(nvp, &proto);
+		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &ifname);
+		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &aobjname);
+	}
+
+	return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
+}
+
+/*
+ * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
+ * in private nvpairs `proto', `ifname' & `aobjname'.
+ */
+static boolean_t
+ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
+    const char *ifname, char *aobjname)
+{
+	char		*db_ifname = NULL, *db_proto = NULL;
+	char		*db_aobjname = NULL;
+	nvpair_t	*nvp;
+	char		*name;
+
+	/* walk through db_nvl and retrieve all private nvpairs */
+	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_proto);
+		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_ifname);
+		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
+			(void) nvpair_value_string(nvp, &db_aobjname);
+	}
+
+	if (proto != NULL && proto[0] != '\0') {
+		if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
+			return (B_FALSE);
+	}
+	if (ifname != NULL && ifname[0] != '\0') {
+		if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
+			return (B_FALSE);
+	}
+	if (aobjname != NULL && aobjname[0] != '\0') {
+		if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
+			return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * Retrieves the property value from the DB. The property whose value is to be
+ * retrieved is in `pargp->ia_pname'.
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_prop_arg_t	*pargp = arg;
+	boolean_t		cont = B_TRUE;
+	char			*pval;
+	int			err = 0;
+
+	*errp = 0;
+
+	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
+	    pargp->ia_ifname, pargp->ia_aobjname))
+		return (B_TRUE);
+
+	if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
+	    &pval)) == 0) {
+		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
+		/*
+		 * We have retrieved what we are looking for.
+		 * Stop the walker.
+		 */
+		cont = B_FALSE;
+	} else {
+		if (err == ENOENT)
+			err = 0;
+		*errp = err;
+	}
+
+	return (cont);
+}
+
+/*
+ * Removes the property value from the DB. The property whose value is to be
+ * removed is in `pargp->ia_pname'.
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_prop_arg_t	*pargp = arg;
+
+	*errp = 0;
+	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
+	    pargp->ia_ifname, pargp->ia_aobjname))
+		return (B_TRUE);
+
+	if (!nvlist_exists(db_nvl, pargp->ia_pname))
+		return (B_TRUE);
+
+	/*
+	 * We found the property in the DB. If IPMGMT_REMOVE is not set then
+	 * delete the entry from the db. If it is set, then the property is a
+	 * multi-valued property so just remove the specified values from DB.
+	 */
+	if (pargp->ia_flags & IPMGMT_REMOVE) {
+		char	*dbpval = NULL;
+		char	*inpval = pargp->ia_pval;
+		char	pval[MAXPROPVALLEN];
+		char	*val, *lasts;
+
+		*errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
+		if (*errp != 0)
+			return (B_FALSE);
+
+		/*
+		 * multi-valued properties are represented as comma separated
+		 * values. Use string tokenizer functions to split them and
+		 * search for the value to be removed.
+		 */
+		bzero(pval, sizeof (pval));
+		if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
+			if (strcmp(val, inpval) != 0)
+				(void) strlcat(pval, val, MAXPROPVALLEN);
+			while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
+				if (strcmp(val, inpval) != 0) {
+					if (pval[0] != '\0')
+						(void) strlcat(pval, ",",
+						    MAXPROPVALLEN);
+					(void) strlcat(pval, val,
+					    MAXPROPVALLEN);
+				}
+			}
+		} else {
+			if (strcmp(dbpval, inpval) != 0)
+				*errp = ENOENT;
+			else
+				buf[0] =  '\0';
+			return (B_FALSE);
+		}
+		*errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
+		if (*errp != 0)
+			return (B_FALSE);
+
+		(void) memset(buf, 0, buflen);
+		if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
+			/* buffer overflow */
+			*errp = ENOBUFS;
+		}
+	} else {
+		buf[0] = '\0';
+	}
+
+	/* stop the search */
+	return (B_FALSE);
+}
+
+/*
+ * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
+ * found, when one of the following occurs first.
+ * - the input aobjname matches the db aobjname. Return the db address.
+ * - the input interface matches the db interface. Return all the
+ *   matching db lines with addresses.
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_getaddr_cbarg_t	*cbarg = arg;
+	char		*db_aobjname = NULL;
+	char		*db_ifname = NULL;
+	nvlist_t	*db_addr = NULL;
+	char		name[IPMGMT_STRSIZE];
+	nvpair_t	*nvp;
+	boolean_t	add_nvl = B_FALSE;
+
+	/* Parse db nvlist */
+	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+		if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
+			(void) nvpair_value_nvlist(nvp, &db_addr);
+		else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
+			(void) nvpair_value_string(nvp, &db_ifname);
+		else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
+			(void) nvpair_value_string(nvp, &db_aobjname);
+	}
+
+	if (db_aobjname == NULL) /* Not an address */
+		return (B_TRUE);
+
+	/* Check for a match between the aobjnames or the interface name */
+	if (cbarg->cb_aobjname[0] != '\0') {
+		if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
+			add_nvl = B_TRUE;
+	} else if (cbarg->cb_ifname[0] != '\0') {
+		if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
+			add_nvl = B_TRUE;
+	} else {
+		add_nvl = B_TRUE;
+	}
+
+	if (add_nvl) {
+		(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
+		    cbarg->cb_ocnt);
+		*errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
+		if (*errp == 0)
+			cbarg->cb_ocnt++;
+	}
+	return (B_TRUE);
+}
+
+/*
+ * This function takes the appropriate lock, read or write, based on the
+ * `db_op' and then calls DB walker ipadm_rw_db().
+ */
+extern int
+ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
+{
+	int		err;
+	boolean_t	writeop;
+	mode_t		mode;
+
+	writeop = (db_op != IPADM_DB_READ);
+
+	if (writeop) {
+		(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
+		mode = IPADM_FILE_MODE;
+	} else {
+		(void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
+		mode = 0;
+	}
+
+	err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE, mode, db_op);
+	(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
+	return (err);
+}
+
+/*
+ * Used to add an entry towards the end of DB. It just returns B_TRUE for
+ * every line of the DB. When we reach the end, ipadm_rw_db() adds the
+ * line at the end.
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
+{
+	return (B_TRUE);
+}
+
+/*
+ * This function is used to update or create an entry in DB. The nvlist_t,
+ * `in_nvl', represents the line we are looking for. Once we ensure the right
+ * line from DB, we update that entry.
+ */
+boolean_t
+ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipadm_dbwrite_cbarg_t	*cb = arg;
+	uint_t			flags = cb->dbw_flags;
+	nvlist_t		*in_nvl = cb->dbw_nvl;
+	nvpair_t		*nvp;
+	char			*name, *instrval = NULL, *dbstrval = NULL;
+	char			pval[MAXPROPVALLEN];
+
+	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
+		return (B_TRUE);
+
+	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
+			break;
+	}
+
+	if (nvp == NULL)
+		return (B_TRUE);
+
+	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
+
+	if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
+		return (B_FALSE);
+
+	/*
+	 * If IPMGMT_APPEND is set then we are dealing with multi-valued
+	 * properties. We append to the entry from the db, with the new value.
+	 */
+	if (flags & IPMGMT_APPEND) {
+		if ((*errp = nvlist_lookup_string(db_nvl, name,
+		    &dbstrval)) != 0)
+			return (B_FALSE);
+		(void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
+		    instrval);
+		if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
+			return (B_FALSE);
+	} else {
+		/* case	of in-line update of a db entry */
+		if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
+			return (B_FALSE);
+	}
+
+	(void) memset(buf, 0, buflen);
+	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
+		/* buffer overflow */
+		*errp = ENOBUFS;
+	}
+	*errp = 0;
+
+	/* we updated the DB entry, so do not continue */
+	return (B_FALSE);
+}
+
+/*
+ * For the given `cbarg->cb_ifname' interface, retrieves any persistent
+ * interface information (used in 'ipadm show-if')
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_getif_cbarg_t	*cbarg = arg;
+	char			*ifname = cbarg->cb_ifname;
+	char			*intf = NULL;
+	ipadm_if_info_t		*ifp = NULL;
+	sa_family_t		af;
+	char			*afstr;
+
+	*errp = 0;
+	if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
+	    nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
+	    (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
+		return (B_TRUE);
+	}
+	af = atoi(afstr);
+	for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
+		if (strcmp(ifp->ifi_name, intf) == 0)
+			break;
+	}
+	if (ifp == NULL) {
+		ipadm_if_info_t *new;
+
+		if ((new = calloc(1, sizeof (*new))) == NULL) {
+			*errp = ENOMEM;
+			return (B_FALSE); /* don't continue the walk */
+		}
+		new->ifi_next = cbarg->cb_ifinfo;
+		cbarg->cb_ifinfo = new;
+		ifp = new;
+		(void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
+	}
+
+	if (af == AF_INET) {
+		ifp->ifi_pflags |= IFIF_IPV4;
+	} else {
+		assert(af == AF_INET6);
+		ifp->ifi_pflags |= IFIF_IPV6;
+	}
+
+	/* Terminate the walk if we found both v4 and v6 interfaces. */
+	if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
+	    (ifp->ifi_pflags & IFIF_IPV6))
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
+/*
+ * Deletes those entries from the database for which interface name
+ * matches with the given `cbarg->cb_ifname'
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_if_cbarg_t *cbarg = arg;
+	boolean_t	isv6 = (cbarg->cb_family == AF_INET6);
+	char		*ifname = cbarg->cb_ifname;
+	char		*modstr = NULL;
+	char		*afstr;
+	char		*aobjname;
+	uint_t		proto;
+	ipmgmt_aobjmap_t *head;
+	boolean_t	aobjfound = B_FALSE;
+
+	*errp = 0;
+
+	if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
+		return (B_TRUE);
+
+	if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
+		if (atoi(afstr) == cbarg->cb_family)
+			goto delete;
+		return (B_TRUE);
+	}
+
+	/* Reset all the interface configurations for 'ifname' */
+	if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
+	    nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
+		goto delete;
+	}
+	if (!isv6 &&
+	    (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
+	    nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
+		goto delete;
+	}
+
+	if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
+		/*
+		 * This must be an address property. Delete this
+		 * line if there is a match in the address family.
+		 */
+		head = aobjmap.aobjmap_head;
+		while (head != NULL) {
+			if (strcmp(head->am_aobjname, aobjname) == 0) {
+				aobjfound = B_TRUE;
+				if (head->am_family == cbarg->cb_family)
+					goto delete;
+			}
+			head = head->am_next;
+		}
+		/*
+		 * If aobjfound = B_FALSE, then this address is not
+		 * available in active configuration. We should go ahead
+		 * and delete it.
+		 */
+		if (!aobjfound)
+			goto delete;
+	}
+
+	/*
+	 * If we are removing both v4 and v6 interface, then we get rid of
+	 * all the properties for that interface. On the other hand, if we
+	 * are deleting only v4 instance of an interface, then we delete v4
+	 * properties only.
+	 */
+	if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
+		proto = ipadm_str2proto(modstr);
+		switch (proto) {
+		case MOD_PROTO_IPV6:
+			if (isv6)
+				goto delete;
+			break;
+		case MOD_PROTO_IPV4:
+			if (!isv6)
+				goto delete;
+			break;
+		case MOD_PROTO_IP:
+			/* this should never be the case, today */
+			assert(0);
+			break;
+		}
+	}
+	/* Not found a match yet. Continue processing the db */
+	return (B_TRUE);
+delete:
+	/* delete the line from the db */
+	buf[0] = '\0';
+	return (B_TRUE);
+}
+
+/*
+ * Deletes those entries from the database for which address object name
+ * matches with the given `cbarg->cb_aobjname'
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_resetaddr_cbarg_t *cbarg = arg;
+	char		*aobjname = cbarg->cb_aobjname;
+
+	*errp = 0;
+	if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
+		return (B_TRUE);
+
+	/* delete the line from the db */
+	buf[0] = '\0';
+	return (B_TRUE);
+}
+
+/*
+ * Retrieves all interface props, including addresses, for given interface(s).
+ * `invl' contains the list of interfaces, for which information need to be
+ * retrieved.
+ */
+/* ARGSUSED */
+boolean_t
+ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipmgmt_initif_cbarg_t	*cbarg = arg;
+	nvlist_t		*onvl = cbarg->cb_onvl;
+	nvlist_t		*invl = cbarg->cb_invl;
+	sa_family_t		in_af = cbarg->cb_family;
+	char			*db_ifname;
+
+	*errp = 0;
+	if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
+	    nvlist_exists(invl, db_ifname)) {
+		char		name[IPMGMT_STRSIZE];
+		sa_family_t	db_af = in_af;
+		uint_t		proto;
+		char		*pstr;
+
+		if (in_af != AF_UNSPEC) {
+			if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
+			    &pstr) == 0) {
+				proto = ipadm_str2proto(pstr);
+				if (proto == MOD_PROTO_IPV4)
+					db_af = AF_INET;
+				else if (proto == MOD_PROTO_IPV6)
+					db_af = AF_INET6;
+				else
+					db_af = in_af;
+			} else {
+				if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
+				    nvlist_exists(db_nvl, IPADM_NVP_DHCP))
+					db_af = AF_INET;
+				else
+					db_af = AF_INET6;
+			}
+		}
+		if (in_af == db_af) {
+			(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
+			    cbarg->cb_ocnt);
+			*errp = nvlist_add_nvlist(onvl, name, db_nvl);
+			if (*errp == 0)
+				cbarg->cb_ocnt++;
+		}
+	}
+	return (B_TRUE);
+}
+
+/*
+ * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
+ * into `aobjmap' structure.
+ */
+static int
+i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
+{
+	ipmgmt_aobjmap_t	*new, *head;
+
+	head = aobjmap.aobjmap_head;
+	if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
+		return (ENOMEM);
+	*new = *nodep;
+	new->am_next = NULL;
+
+	/* Add the node at the beginning of the list */
+	if (head == NULL) {
+		aobjmap.aobjmap_head = new;
+	} else {
+		new->am_next = aobjmap.aobjmap_head;
+		aobjmap.aobjmap_head = new;
+	}
+	return (0);
+}
+
+/*
+ * A recursive function to generate alphabetized number given a decimal number.
+ * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
+ * 'ab', 'ac', et al.
+ */
+static void
+i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
+{
+	if (num >= 26)
+		i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
+	if (*cp != endp) {
+		*cp[0] = 'a' + (num % 26);
+		(*cp)++;
+	}
+}
+
+/*
+ * This function generates an `aobjname', when required, and then does
+ * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
+ * through the `aobjmap' to check if an address object with the same
+ * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
+ * `aobjname's are not allowed.
+ *
+ * If `nodep->am_aobjname' is an empty string then the daemon generates an
+ * `aobjname' using the `am_nextnum', which contains the next number to be
+ * used to generate `aobjname'. `am_nextnum' is converted to base26 using
+ * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
+ *
+ * `am_nextnum' will be 0 to begin with. Every time an address object that
+ * needs `aobjname' is added it's incremented by 1. So for the first address
+ * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
+ * For the second address object on that interface `am_aobjname' will be net0/_b
+ * and  `am_nextnum' will incremented to 2.
+ */
+static int
+i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
+{
+	ipmgmt_aobjmap_t	*head;
+	uint32_t		nextnum;
+
+	for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
+		if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
+			break;
+	nextnum = (head == NULL ? 0 : head->am_nextnum);
+
+	/*
+	 * if `aobjname' is empty, then the daemon has to generate the
+	 * next `aobjname' for the given interface and family.
+	 */
+	if (nodep->am_aobjname[0] == '\0') {
+		char tmpstr[IPADM_AOBJ_USTRSIZ - 1];  /* 1 for leading  '_' */
+		char *cp = tmpstr;
+		char *endp = tmpstr + sizeof (tmpstr);
+
+		i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
+
+		if (cp == endp)
+			return (EINVAL);
+		cp[0] = '\0';
+
+		if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
+		    nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
+			return (EINVAL);
+		}
+		nodep->am_nextnum = ++nextnum;
+	} else {
+		for (head = aobjmap.aobjmap_head; head != NULL;
+		    head = head->am_next) {
+			if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
+				return (EEXIST);
+		}
+		nodep->am_nextnum = nextnum;
+	}
+	return (i_ipmgmt_add_amnode(nodep));
+}
+
+/*
+ * Performs following operations on the global `aobjmap' linked list.
+ * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
+ * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
+ * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
+ */
+int
+ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
+{
+	ipmgmt_aobjmap_t	*head, *prev;
+	boolean_t		update = B_TRUE;
+	int			err = 0;
+	ipadm_db_op_t		db_op;
+
+	(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
+
+	head = aobjmap.aobjmap_head;
+	switch (op) {
+	case ADDROBJ_ADD:
+		/*
+		 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
+		 * update, else add the new node.
+		 */
+		for (; head != NULL; head = head->am_next) {
+			if (strcmp(head->am_aobjname,
+			    nodep->am_aobjname) == 0 && head->am_lnum == -1)
+				break;
+		}
+
+		if (head != NULL) {
+			/* update the node */
+			(void) strlcpy(head->am_ifname, nodep->am_ifname,
+			    sizeof (head->am_ifname));
+			head->am_lnum = nodep->am_lnum;
+			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;
+			}
+		} else {
+			for (head = aobjmap.aobjmap_head; head != NULL;
+			    head = head->am_next) {
+				if (strcmp(head->am_ifname,
+				    nodep->am_ifname) == 0)
+					break;
+			}
+			nodep->am_nextnum = (head == NULL ? 0 :
+			    head->am_nextnum);
+			err = i_ipmgmt_add_amnode(nodep);
+		}
+		db_op = IPADM_DB_WRITE;
+		break;
+	case ADDROBJ_DELETE:
+		prev = head;
+		while (head != NULL) {
+			if (strcmp(head->am_aobjname,
+			    nodep->am_aobjname) == 0) {
+				nodep->am_atype = head->am_atype;
+				/*
+				 * There could be multiple IPV6_ADDRCONF nodes,
+				 * with same address object name, so check for
+				 * logical number also.
+				 */
+				if (head->am_atype !=
+				    IPADM_ADDR_IPV6_ADDRCONF ||
+				    nodep->am_lnum == head->am_lnum)
+					break;
+			}
+			prev = head;
+			head = head->am_next;
+		}
+		if (head != NULL) {
+			/*
+			 * If the address object is in both active and
+			 * persistent configuration and the user is deleting it
+			 * only from active configuration then mark this node
+			 * for deletion by reseting IPMGMT_ACTIVE bit.
+			 * With this the same address object name cannot
+			 * be reused until it is permanently removed.
+			 */
+			if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
+			    nodep->am_flags == IPMGMT_ACTIVE) {
+				/* Update flags in the in-memory map. */
+				head->am_flags &= ~IPMGMT_ACTIVE;
+				head->am_lnum = -1;
+
+				/* Update info in file. */
+				db_op = IPADM_DB_WRITE;
+				*nodep = *head;
+			} else {
+				(void) strlcpy(nodep->am_ifname,
+				    head->am_ifname,
+				    sizeof (nodep->am_ifname));
+				/* otherwise delete the node */
+				if (head == aobjmap.aobjmap_head)
+					aobjmap.aobjmap_head = head->am_next;
+				else
+					prev->am_next = head->am_next;
+				free(head);
+				db_op = IPADM_DB_DELETE;
+			}
+		} else {
+			err = ENOENT;
+		}
+		break;
+	case ADDROBJ_LOOKUPADD:
+		err = i_ipmgmt_lookupadd_amnode(nodep);
+		update = B_FALSE;
+		break;
+	default:
+		assert(0);
+	}
+
+	if (err == 0 && update)
+		err = ipmgmt_persist_aobjmap(nodep, db_op);
+
+	(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
+
+	return (err);
+}
+
+/*
+ * Given a node in `aobjmap', this function converts it into nvlist_t structure.
+ * The content to be written to DB must be represented as nvlist_t.
+ */
+static int
+i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
+{
+	int	err;
+	char	strval[IPMGMT_STRSIZE];
+
+	*nvl = NULL;
+	if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
+		goto fail;
+
+	if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
+	    np->am_aobjname)) != 0)
+		goto fail;
+
+	if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
+	    np->am_ifname)) != 0)
+		goto fail;
+
+	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
+	if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
+		goto fail;
+
+	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
+	if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
+		goto fail;
+
+	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
+	if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
+		goto fail;
+
+	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
+	if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
+		goto fail;
+
+	if (np->am_atype == 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;
+			}
+			if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
+			    strval)) != 0)
+				goto fail;
+		}
+	} else {
+		if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
+		    "")) != 0)
+			goto fail;
+	}
+	return (err);
+fail:
+	nvlist_free(*nvl);
+	return (err);
+}
+
+/*
+ * Read the aobjmap data store and build the in-memory representation
+ * of the aobjmap. We don't need to hold any locks while building this as
+ * we do this in very early stage of daemon coming up, even before the door
+ * is opened.
+ */
+/* ARGSUSED */
+extern boolean_t
+ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	nvpair_t		*nvp = NULL;
+	char			*name, *strval = NULL;
+	ipmgmt_aobjmap_t 	node;
+	struct sockaddr_in6	*in6;
+
+	*errp = 0;
+	node.am_next = NULL;
+	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+		name = nvpair_name(nvp);
+
+		if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
+			return (B_TRUE);
+		if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
+			(void) strlcpy(node.am_aobjname, strval,
+			    sizeof (node.am_aobjname));
+		} else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
+			(void) strlcpy(node.am_ifname, strval,
+			    sizeof (node.am_ifname));
+		} else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
+			node.am_lnum = atoi(strval);
+		} else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
+			node.am_family = (sa_family_t)atoi(strval);
+		} else if (strcmp(FLAGS, name) == 0) {
+			node.am_flags = atoi(strval);
+		} else if (strcmp(ATYPE, name) == 0) {
+			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;
+				if (strcmp(strval, "default") == 0) {
+					bzero(in6, sizeof (node.am_ifid));
+					node.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;
+				}
+			}
+		}
+	}
+
+	/* we have all the information we need, add the node */
+	*errp = i_ipmgmt_add_amnode(&node);
+
+	return (B_TRUE);
+}
+
+/*
+ * Updates an entry from the temporary cache file, which matches the given
+ * address object name.
+ */
+/* ARGSUSED */
+static boolean_t
+ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
+    size_t buflen, int *errp)
+{
+	ipadm_dbwrite_cbarg_t	*cb = arg;
+	nvlist_t		*in_nvl = cb->dbw_nvl;
+	uint32_t		flags = cb->dbw_flags;
+	char			*db_lifnumstr = NULL, *in_lifnumstr = NULL;
+
+	*errp = 0;
+	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
+		return (B_TRUE);
+
+	if (flags & IPMGMT_ATYPE_V6ACONF) {
+		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
+		    &db_lifnumstr) != 0 ||
+		    nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
+		    &in_lifnumstr) != 0 ||
+		    (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
+		    strcmp(db_lifnumstr, in_lifnumstr) != 0))
+			return (B_TRUE);
+	}
+
+	/* we found the match */
+	(void) memset(buf, 0, buflen);
+	if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
+		/* buffer overflow */
+		*errp = ENOBUFS;
+	}
+
+	/* stop the walker */
+	return (B_FALSE);
+}
+
+/*
+ * Deletes an entry from the temporary cache file, which matches the given
+ * address object name.
+ */
+/* ARGSUSED */
+static boolean_t
+ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
+    size_t buflen, int *errp)
+{
+	ipmgmt_aobjmap_t	*nodep = arg;
+	char			*db_lifnumstr = NULL;
+
+	*errp = 0;
+	if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
+	    nodep->am_aobjname))
+		return (B_TRUE);
+
+	if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
+		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
+		    &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
+			return (B_TRUE);
+	}
+
+	/* we found the match, delete the line from the db */
+	buf[0] = '\0';
+
+	/* stop the walker */
+	return (B_FALSE);
+}
+
+/*
+ * Adds or deletes aobjmap node information into a temporary cache file.
+ */
+extern int
+ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
+{
+	int			err;
+	ipadm_dbwrite_cbarg_t	cb;
+	nvlist_t		*nvl = NULL;
+
+	if (op == IPADM_DB_WRITE) {
+		if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
+			return (err);
+		cb.dbw_nvl = nvl;
+		if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
+			cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
+		else
+			cb.dbw_flags = 0;
+
+		err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
+		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
+		nvlist_free(nvl);
+	} else {
+		assert(op == IPADM_DB_DELETE);
+
+		err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
+		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
+	}
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Utility functions used by the ipmgmtd daemon.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include "ipmgmt_impl.h"
+
+void
+ipmgmt_log(int pri, const char *fmt, ...)
+{
+	va_list alist;
+
+	va_start(alist, fmt);
+	vsyslog(pri, fmt, alist);
+	va_end(alist);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,62 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# This daemon stores address object to logical interface number mappings
+# (among other things) and reads/writes from/to ipmgmtd data store.
+#
+
+. /lib/svc/share/smf_include.sh
+
+if [ -z "$SMF_FMRI" ]; then
+        echo "this script can only be invoked by smf(5)"        
+        exit $SMF_EXIT_ERR_NOSMF
+fi
+
+#
+# network/ip-interface-management:default service is always enabled by default.
+# When the non-global shared-IP stack zone boots, it tries to bring up this
+# service as well. If we don't start a background process and simply exit the
+# service, the service will go into maintenance mode and so will all it's
+# dependents.
+#
+if smf_is_nonglobalzone; then
+	if [ `/sbin/zonename -t` = shared ]; then
+		(while true ; do sleep 3600 ; done) & 
+		exit $SMF_EXIT_OK
+	fi
+fi
+
+# Apply any persistent protocol (IP/TCP/SCTP/UDP/ICMP) properties
+/sbin/ipadm init-prop
+
+#
+# We must be now in a global zone or non-global zone with exclusive-IP stack.
+# Start the ipmgmtd daemon.
+#
+if /lib/inet/ipmgmtd ; then
+	exit $SMF_EXIT_OK
+else
+        exit $SMF_EXIT_ERR_FATAL
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ 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]
+
+ CDDL HEADER END
+
+	NOTE:  This service manifest is not editable; its contents will
+	be overwritten by package or patch operations, including
+	operating system upgrade.  Make customizations in a different
+	file.
+-->
+
+<service_bundle type='manifest' name='SUNWcsr:ipmgmtd'>
+
+<service
+	name='network/ip-interface-management'
+	type='service'
+	version='1'>
+
+	<create_default_instance enabled='true' />
+
+	<single_instance />
+
+	<dependent name='ipmgmt-loopback'
+		grouping='require_all'
+		restart_on='none'>
+		<service_fmri value='svc:/network/loopback' />
+	</dependent>
+
+        <dependent name='ipmgmt-physical'
+                grouping='require_all'
+                restart_on='none'>
+                <service_fmri value='svc:/network/physical' />
+        </dependent>
+
+        <dependent name='ipmgmt-iptun'
+                grouping='require_all'
+                restart_on='none'>
+                <service_fmri value='svc:/network/iptun' />
+        </dependent>
+
+	<exec_method
+		type='method'
+		name='start'
+		exec='/lib/svc/method/net-ipmgmt'
+		timeout_seconds='60' />
+
+	<exec_method
+		type='method'
+		name='stop'
+		exec=':kill'
+		timeout_seconds='5' />
+
+	<stability value='Unstable' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+				IP interface management
+			</loctext>
+		</common_name>
+		<description>
+			<loctext xml:lang='C'>
+				Create IP interfaces, apply
+				TCP/IP properties and manage
+				address object mappings.
+			</loctext>
+		</description>
+		<documentation>
+			<manpage title='ipadm' section='1M'
+				manpath='/usr/share/man' />
+		</documentation>
+	</template>
+</service>
+
+</service_bundle>
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -18,11 +18,9 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # cmd/cmd-inet/usr.lib/in.ndpd/Makefile
 #
 
@@ -41,12 +39,12 @@
 # be accessed by -lxnet. In addition -lsocket and -lnsl are used to
 # capture new not-yet-standard interfaces. Someday -lxnet alone should be enough
 # when IPv6 inspired new interfaces are part of standards.
-LDLIBS +=	-ldhcpagent -lxnet -lsocket -lnsl
+LDLIBS +=	-ldhcpagent -lxnet -lsocket -lnsl -lipadm
 
 # these #defines are required to use UNIX 98 interfaces
 _D_UNIX98_EXTN= -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
 
-$(OBJS)		:= CPPFLAGS +=	$(_D_UNIX98_EXTN)
+$(OBJS)		:= CPPFLAGS +=  $(_D_UNIX98_EXTN)
 
 LINTFLAGS +=	$(_D_UNIX98_EXTN)
 
@@ -58,6 +56,10 @@
 # perfect would require a bigger rewrite.
 LINTFLAGS +=	-erroff=E_BAD_PTR_CAST_ALIGN
 
+CTFCONVERT_HOOK = && $(CTFCONVERT_O)
+CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS)
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+
 .KEEP_STATE:
 
 .PARALLEL:  $(OBJS)
@@ -65,7 +67,7 @@
 all: $(PROG)
 
 $(PROG): $(OBJS)
-	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE_HOOK)
 	$(POST_PROCESS)
 
 include		../Makefile.lib
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_NDPD_DEFS_H
 #define	_NDPD_DEFS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -62,6 +60,8 @@
 #include <netinet/ip6.h>
 #include <netinet/icmp6.h>
 #include <net/route.h>
+#include <libipadm.h>
+#include <ipadm_ndpd.h>
 
 #include "tables.h"
 
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c	Fri Mar 26 17:53:11 2010 -0400
@@ -18,7 +18,7 @@
  *
  * CDDL HEADER END
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -91,7 +91,22 @@
 struct	rt_msghdr	*rt_msg;	/* Routing socket message */
 struct	sockaddr_in6	*rta_gateway;	/* RTA_GATEWAY sockaddr */
 struct	sockaddr_dl	*rta_ifp;	/* RTA_IFP sockaddr */
-int	mibsock = -1;			/* mib request socket */
+
+/*
+ * These sockets are used internally in this file.
+ */
+static int	mibsock = -1;			/* mib request socket */
+static int	cmdsock = -1;			/* command socket */
+
+static	int	ndpd_setup_cmd_listener(void);
+static	void	ndpd_cmd_handler(int);
+static	int	ndpd_process_cmd(int, ipadm_ndpd_msg_t *);
+static	int	ndpd_send_error(int, int);
+static	int	ndpd_set_autoconf(const char *, boolean_t);
+static	int	ndpd_create_addrs(const char *, struct sockaddr_in6, int,
+    boolean_t, boolean_t, char *);
+static	int	ndpd_delete_addrs(const char *);
+static	int	phyint_check_ipadm_intfid(struct phyint *);
 
 /*
  * Return the current time in milliseconds truncated to
@@ -361,7 +376,7 @@
 	new_num = pollfd_num + 32;
 	newfds = realloc(pollfds, new_num * sizeof (struct pollfd));
 	if (newfds == NULL) {
-		logperror("poll_add: realloc");
+		logperror("realloc");
 		return (-1);
 	}
 
@@ -449,20 +464,27 @@
 
 	pi = phyint_lookup(phyintname);
 	if (pi == NULL) {
-		/*
-		 * Do not add anything for new interfaces until they are UP.
-		 * For existing interfaces we track the up flag.
-		 */
-		if (!(lifr.lifr_flags & IFF_UP))
-			return;
-
 		pi = phyint_create(phyintname);
 		if (pi == NULL) {
 			logmsg(LOG_ERR, "if_process: out of memory\n");
 			return;
 		}
+		/*
+		 * if in.ndpd is restarted, check with ipmgmtd if there is any
+		 * interface id to be configured for this interface.
+		 */
+		if (first) {
+			if (phyint_check_ipadm_intfid(pi) == -1)
+				logmsg(LOG_ERR, "Could not get ipadm info\n");
+		}
+	} else {
+		/*
+		 * if the phyint already exists, synchronize it with
+		 * the kernel state. For a newly created phyint, phyint_create
+		 * calls phyint_init_from_k().
+		 */
+		(void) phyint_init_from_k(pi);
 	}
-	(void) phyint_init_from_k(pi);
 	if (pi->pi_sock == -1 && !(pi->pi_kernel_state & PI_PRESENT)) {
 		/* Interface is not yet present */
 		if (debug & D_PHYINT) {
@@ -1088,7 +1110,7 @@
 				    "found on %s; assuming default flags\n",
 				    pi->pi_name);
 			}
-			if (pi->pi_StatefulAddrConf) {
+			if (pi->pi_autoconf && pi->pi_StatefulAddrConf) {
 				pi->pi_ra_flags |= ND_RA_FLAG_MANAGED |
 				    ND_RA_FLAG_OTHER;
 				start_dhcp(pi);
@@ -1376,6 +1398,12 @@
 			if (pi->pi_AdvSendAdvertisements)
 				check_to_advertise(pi, START_FINAL_ADV);
 
+			/*
+			 * Remove all the configured addresses.
+			 * Remove the addrobj names created with ipmgmtd.
+			 * Release the dhcpv6 addresses if any.
+			 * Cleanup the phyints.
+			 */
 			phyint_delete(pi);
 		}
 
@@ -1411,7 +1439,7 @@
 		/* NOTREACHED */
 	case 255:
 		/*
-		 * Special "signal" from looback_ra_enqueue.
+		 * Special "signal" from loopback_ra_enqueue.
 		 * Handle any queued loopback router advertisements.
 		 */
 		loopback_ra_dequeue();
@@ -1838,6 +1866,8 @@
 		if (!pr->pr_in_use) {
 			/* Clear everything except PR_STATIC */
 			pr->pr_kernel_state &= PR_STATIC;
+			if (pr->pr_state & PR_STATIC)
+				prefix_update_ipadm_addrobj(pr, _B_FALSE);
 			pr->pr_name[0] = '\0';
 			if (pr->pr_state & PR_STATIC) {
 				prefix_delete(pr);
@@ -1870,6 +1900,7 @@
 		for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
 			next_pr = pr->pr_next;
 			if (pr->pr_state & PR_AUTO)
+				prefix_update_ipadm_addrobj(pr, _B_FALSE);
 				prefix_delete(pr);
 		}
 
@@ -2033,10 +2064,10 @@
 	if (show_ifs)
 		phyint_print_all();
 
-	if (debug == 0) {
+	if (debug == 0)
 		initlog();
-	}
 
+	cmdsock = ndpd_setup_cmd_listener();
 	setup_eventpipe();
 	rtsock = setup_rtsock();
 	mibsock = setup_mibsock();
@@ -2067,6 +2098,10 @@
 				process_mibsock(mibsock);
 				break;
 			}
+			if (pollfds[i].fd == cmdsock) {
+				ndpd_cmd_handler(cmdsock);
+				break;
+			}
 			/*
 			 * Run timer routine to advance clock if more than
 			 * half a second since the clock was advanced.
@@ -2167,3 +2202,417 @@
 		    strerror(errno));
 	}
 }
+
+static int
+ndpd_setup_cmd_listener(void)
+{
+	int sock;
+	int ret;
+	struct sockaddr_un servaddr;
+
+	sock = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (sock < 0) {
+		logperror("socket");
+		exit(1);
+	}
+
+	bzero(&servaddr, sizeof (servaddr));
+	servaddr.sun_family = AF_UNIX;
+	(void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH,
+	    sizeof (servaddr.sun_path));
+	(void) unlink(servaddr.sun_path);
+	ret = bind(sock, (struct sockaddr *)&servaddr, sizeof (servaddr));
+	if (ret < 0) {
+		logperror("bind");
+		exit(1);
+	}
+	if (listen(sock, 30) < 0) {
+		logperror("listen");
+		exit(1);
+	}
+	if (poll_add(sock) == -1) {
+		logmsg(LOG_ERR, "command socket could not be added to the "
+		    "polling set\n");
+		exit(1);
+	}
+
+	return (sock);
+}
+
+/*
+ * Commands received over the command socket come here
+ */
+static void
+ndpd_cmd_handler(int sock)
+{
+	int			newfd;
+	struct sockaddr_storage	peer;
+	socklen_t		peerlen;
+	ipadm_ndpd_msg_t	ndpd_msg;
+	int			retval;
+
+	peerlen = sizeof (peer);
+	newfd = accept(sock, (struct sockaddr *)&peer, &peerlen);
+	if (newfd < 0) {
+		logperror("accept");
+		return;
+	}
+
+	retval = ipadm_ndpd_read(newfd, &ndpd_msg, sizeof (ndpd_msg));
+	if (retval != 0)
+		logperror("Could not read ndpd command");
+
+	retval = ndpd_process_cmd(newfd, &ndpd_msg);
+	if (retval != 0) {
+		logmsg(LOG_ERR, "ndpd command on interface %s failed with "
+		    "error %s\n", ndpd_msg.inm_ifname, strerror(retval));
+	}
+	(void) close(newfd);
+}
+
+/*
+ * Process the commands received from the cmd listener socket.
+ */
+static int
+ndpd_process_cmd(int newfd, ipadm_ndpd_msg_t *msg)
+{
+	int err;
+
+	if (!ipadm_check_auth()) {
+		logmsg(LOG_ERR, "User not authorized to send the command\n");
+		(void) ndpd_send_error(newfd, EPERM);
+		return (EPERM);
+	}
+	switch (msg->inm_cmd) {
+	case IPADM_DISABLE_AUTOCONF:
+		err = ndpd_set_autoconf(msg->inm_ifname, _B_FALSE);
+		break;
+
+	case IPADM_ENABLE_AUTOCONF:
+		err = ndpd_set_autoconf(msg->inm_ifname, _B_TRUE);
+		break;
+
+	case IPADM_CREATE_ADDRS:
+		err = ndpd_create_addrs(msg->inm_ifname, msg->inm_intfid,
+		    msg->inm_intfidlen, msg->inm_stateless,
+		    msg->inm_stateful, msg->inm_aobjname);
+		break;
+
+	case IPADM_DELETE_ADDRS:
+		err = ndpd_delete_addrs(msg->inm_ifname);
+		break;
+
+	default:
+		err = EINVAL;
+		break;
+	}
+
+	(void) ndpd_send_error(newfd, err);
+
+	return (err);
+}
+
+static int
+ndpd_send_error(int fd, int error)
+{
+	return (ipadm_ndpd_write(fd, &error, sizeof (error)));
+}
+
+/*
+ * Disables/Enables autoconfiguration of addresses on the
+ * given physical interface.
+ * This is provided to support the legacy method of configuring IPv6
+ * addresses. i.e. `ifconfig bge0 inet6 plumb` will plumb the interface
+ * and start stateless and stateful autoconfiguration. If this function is
+ * not called with enable=_B_FALSE, no autoconfiguration will be done until
+ * ndpd_create_addrs() is called with an Interface ID.
+ */
+static int
+ndpd_set_autoconf(const char *ifname, boolean_t enable)
+{
+	struct phyint *pi;
+
+	pi = phyint_lookup((char *)ifname);
+	if (pi == NULL) {
+		/*
+		 * If the physical interface was plumbed but no
+		 * addresses were configured yet, phyint will not exist.
+		 */
+		pi = phyint_create((char *)ifname);
+		if (pi == NULL) {
+			logmsg(LOG_ERR, "could not create phyint for "
+			    "interface %s", ifname);
+			return (ENOMEM);
+		}
+	}
+	pi->pi_autoconf = enable;
+
+	if (debug & D_PHYINT) {
+		logmsg(LOG_DEBUG, "ndpd_set_autoconf: %s autoconf for "
+		    "interface %s\n", (enable ? "enabled" : "disabled"),
+		    pi->pi_name);
+	}
+	return (0);
+}
+
+/*
+ * Create auto-configured addresses on the given interface using
+ * the given token as the interface id during the next Router Advertisement.
+ * Currently, only one token per interface is supported.
+ */
+static int
+ndpd_create_addrs(const char *ifname, struct sockaddr_in6 intfid, int intfidlen,
+    boolean_t stateless, boolean_t stateful, char *addrobj)
+{
+	struct phyint *pi;
+	struct lifreq lifr;
+	struct sockaddr_in6 *sin6;
+	int err;
+
+	pi = phyint_lookup((char *)ifname);
+	if (pi == NULL) {
+		/*
+		 * If the physical interface was plumbed but no
+		 * addresses were configured yet, phyint will not exist.
+		 */
+		pi = phyint_create((char *)ifname);
+		if (pi == NULL) {
+			if (debug & D_PHYINT)
+				logmsg(LOG_ERR, "could not create phyint "
+				    "for interface %s", ifname);
+			return (ENOMEM);
+		}
+	} else if (pi->pi_autoconf) {
+		logmsg(LOG_ERR, "autoconfiguration already in progress\n");
+		return (EEXIST);
+	}
+	check_autoconf_var_consistency(pi, stateless, stateful);
+
+	if (intfidlen == 0) {
+		pi->pi_default_token = _B_TRUE;
+		if (ifsock < 0) {
+			ifsock = socket(AF_INET6, SOCK_DGRAM, 0);
+			if (ifsock < 0) {
+				err = errno;
+				logperror("ndpd_create_addrs: socket");
+				return (err);
+			}
+		}
+		(void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
+		if (ioctl(ifsock, SIOCGLIFTOKEN, (char *)&lifr) < 0) {
+			err = errno;
+			logperror("SIOCGLIFTOKEN");
+			return (err);
+		}
+		pi->pi_token = sin6->sin6_addr;
+		pi->pi_token_length = lifr.lifr_addrlen;
+	} else {
+		pi->pi_default_token = _B_FALSE;
+		pi->pi_token = intfid.sin6_addr;
+		pi->pi_token_length = intfidlen;
+	}
+	pi->pi_stateless = stateless;
+	pi->pi_stateful = stateful;
+	(void) strlcpy(pi->pi_ipadm_aobjname, addrobj,
+	    sizeof (pi->pi_ipadm_aobjname));
+
+	/* We can allow autoconfiguration now. */
+	pi->pi_autoconf = _B_TRUE;
+
+	/* Restart the solicitations. */
+	if (pi->pi_sol_state == DONE_SOLICIT)
+		pi->pi_sol_state = NO_SOLICIT;
+	if (pi->pi_sol_state == NO_SOLICIT)
+		check_to_solicit(pi, START_INIT_SOLICIT);
+	if (debug & D_PHYINT)
+		logmsg(LOG_DEBUG, "ndpd_create_addrs: "
+		    "added token to interface %s\n", pi->pi_name);
+	return (0);
+}
+
+/*
+ * This function deletes all addresses on the given interface
+ * with the given Interface ID.
+ */
+static int
+ndpd_delete_addrs(const char *ifname)
+{
+	struct phyint *pi;
+	struct prefix *pr, *next_pr;
+	struct lifreq lifr;
+	int err;
+
+	pi = phyint_lookup((char *)ifname);
+	if (pi == NULL) {
+		logmsg(LOG_ERR, "no phyint found for %s", ifname);
+		return (ENXIO);
+	}
+	if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_token)) {
+		logmsg(LOG_ERR, "token does not exist for %s", ifname);
+		return (EINVAL);
+	}
+
+	if (ifsock < 0) {
+		ifsock = socket(AF_INET6, SOCK_DGRAM, 0);
+		if (ifsock < 0) {
+			err = errno;
+			logperror("ndpd_create_addrs: socket");
+			return (err);
+		}
+	}
+	/* Remove the prefixes for this phyint if they exist */
+	for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
+		next_pr = pr->pr_next;
+		if (pr->pr_name[0] == '\0') {
+			prefix_delete(pr);
+			continue;
+		}
+		/*
+		 * Delete all the prefixes for the auto-configured
+		 * addresses as well as the DHCPv6 addresses.
+		 */
+		(void) strncpy(lifr.lifr_name, pr->pr_name,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
+			err = errno;
+			logperror("SIOCGLIFFLAGS");
+			return (err);
+		}
+		if ((lifr.lifr_flags & IFF_ADDRCONF) ||
+		    (lifr.lifr_flags & IFF_DHCPRUNNING)) {
+			prefix_update_ipadm_addrobj(pr, _B_FALSE);
+		}
+		prefix_delete(pr);
+	}
+
+	/*
+	 * If we had started dhcpagent, we need to release the leases
+	 * if any are required.
+	 */
+	if (pi->pi_stateful) {
+		(void) strncpy(lifr.lifr_name, pi->pi_name,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(ifsock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
+			err = errno;
+			logperror("SIOCGLIFFLAGS");
+			return (err);
+		}
+		if (lifr.lifr_flags & IFF_DHCPRUNNING)
+			release_dhcp(pi);
+	}
+
+	/*
+	 * Reset the Interface ID on this phyint and stop autoconfigurations
+	 * until a new interface ID is provided.
+	 */
+	pi->pi_token = in6addr_any;
+	pi->pi_token_length = 0;
+	pi->pi_autoconf = _B_FALSE;
+	pi->pi_ipadm_aobjname[0] = '\0';
+
+	/* Reset the stateless and stateful settings to default. */
+	pi->pi_stateless = pi->pi_StatelessAddrConf;
+	pi->pi_stateful = pi->pi_StatefulAddrConf;
+
+	if (debug & D_PHYINT) {
+		logmsg(LOG_DEBUG, "ndpd_delete_addrs: "
+		    "removed token from interface %s\n", pi->pi_name);
+	}
+	return (0);
+}
+
+void
+check_autoconf_var_consistency(struct phyint *pi, boolean_t stateless,
+    boolean_t stateful)
+{
+	/*
+	 * If StatelessAddrConf and StatelessAddrConf are set in
+	 * /etc/inet/ndpd.conf, check if the new values override those
+	 * settings. If so, log a warning.
+	 */
+	if ((pi->pi_StatelessAddrConf !=
+	    ifdefaults[I_StatelessAddrConf].cf_value &&
+	    stateless != pi->pi_StatelessAddrConf) ||
+	    (pi->pi_StatefulAddrConf !=
+	    ifdefaults[I_StatefulAddrConf].cf_value &&
+	    stateful != pi->pi_StatefulAddrConf)) {
+		logmsg(LOG_ERR, "check_autoconf_var_consistency: "
+		    "Overriding the StatelessAddrConf or StatefulAddrConf "
+		    "settings in ndpd.conf with the new values for "
+		    "interface %s\n", pi->pi_name);
+	}
+}
+
+/*
+ * If ipadm was used to start autoconfiguration and in.ndpd was restarted
+ * for some reason, in.ndpd has to resume autoconfiguration when it comes up.
+ * In this function, it scans the ipadm_addr_info() output to find a link-local
+ * on this interface with address type "addrconf" and extracts the interface id.
+ * It also stores the addrobj name to be used later when new addresses are
+ * created for the prefixes advertised by the router.
+ * If autoconfiguration was never started on this interface before in.ndpd
+ * was killed, then in.ndpd should refrain from configuring prefixes, even if
+ * there is a valid link-local on this interface, created by ipadm (identified
+ * if there is a valid addrobj name).
+ */
+static int
+phyint_check_ipadm_intfid(struct phyint *pi)
+{
+	ipadm_status_t		status;
+	ipadm_addr_info_t	*addrinfo;
+	struct ifaddrs		*ifap;
+	ipadm_addr_info_t	*ainfop;
+	struct sockaddr_in6	*sin6;
+	ipadm_handle_t		iph;
+
+	if (ipadm_open(&iph, 0) != IPADM_SUCCESS) {
+		logmsg(LOG_ERR, "could not open handle to libipadm\n");
+		return (-1);
+	}
+
+	status = ipadm_addr_info(iph, pi->pi_name, &addrinfo,
+	    IPADM_OPT_ZEROADDR, LIFC_NOXMIT|LIFC_TEMPORARY);
+	if (status != IPADM_SUCCESS) {
+		ipadm_close(iph);
+		return (-1);
+	}
+	pi->pi_autoconf = _B_TRUE;
+	for (ainfop = addrinfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
+		ifap = &ainfop->ia_ifa;
+		if (ifap->ifa_addr->ss_family != AF_INET6 ||
+		    ainfop->ia_state == IFA_DISABLED)
+			continue;
+		sin6 = (struct sockaddr_in6 *)ifap->ifa_addr;
+		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+			if (ainfop->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
+				pi->pi_token = sin6->sin6_addr;
+				pi->pi_token._S6_un._S6_u32[0] = 0;
+				pi->pi_token._S6_un._S6_u32[1] = 0;
+				pi->pi_autoconf = _B_TRUE;
+				(void) strlcpy(pi->pi_ipadm_aobjname,
+				    ainfop->ia_aobjname,
+				    sizeof (pi->pi_ipadm_aobjname));
+				break;
+			}
+			/*
+			 * If IFF_NOLINKLOCAL is set, then the link-local
+			 * was created using ipadm. Do not autoconfigure until
+			 * ipadm is explicitly used for autoconfiguration.
+			 */
+			if (ifap->ifa_flags & IFF_NOLINKLOCAL)
+				pi->pi_autoconf = _B_FALSE;
+		} else if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+		    strrchr(ifap->ifa_name, ':') == NULL) {
+			/* The interface was created using ipadm. */
+			pi->pi_autoconf = _B_FALSE;
+		}
+	}
+	ipadm_free_addr_info(addrinfo);
+	if (!pi->pi_autoconf) {
+		pi->pi_token = in6addr_any;
+		pi->pi_token_length = 0;
+	}
+	ipadm_close(iph);
+	return (0);
+}
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -307,57 +307,99 @@
 }
 
 /*
- * Start up DHCPv6 on a given physical interface.  Does not wait for a message
- * to be returned from the daemon.
+ * Function that sends commands to dhcpagent daemon.
+ */
+int
+dhcp_op(struct phyint *pi, int type)
+{
+	dhcp_ipc_request_t	*request;
+	dhcp_ipc_reply_t	*reply	= NULL;
+	int			error;
+
+	request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0,
+	    DHCP_TYPE_NONE);
+	if (request == NULL) {
+		logmsg(LOG_ERR, "dhcp_op: out of memory\n");
+		/* make sure we try again next time there's a chance */
+		if (type != DHCP_RELEASE) {
+			pi->pi_ra_flags &=
+			    ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
+		}
+		return (DHCP_IPC_E_MEMORY);
+	}
+
+	error = dhcp_ipc_make_request(request, &reply, 0);
+	free(request);
+	if (error != 0) {
+		logmsg(LOG_ERR, "could not send request to dhcpagent: "
+		    "%s: %s\n", pi->pi_name, dhcp_ipc_strerror(error));
+		return (error);
+	}
+
+	error = reply->return_code;
+	free(reply);
+
+	return (error);
+}
+
+/*
+ * Start up DHCPv6 on a given physical interface. Does not wait for
+ * a message to be returned from the daemon.
  */
 void
 start_dhcp(struct phyint *pi)
 {
-	dhcp_ipc_request_t	*request;
-	dhcp_ipc_reply_t	*reply	= NULL;
-	int			error;
-	int			type;
+	int	error;
+	int	type;
 
 	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
-		logmsg(LOG_ERR, "start_dhcp: unable to start %s\n",
-		    DHCP_AGENT_PATH);
+		logmsg(LOG_ERR, "unable to start %s\n", DHCP_AGENT_PATH);
 		/* make sure we try again next time there's a chance */
 		pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
 		return;
 	}
 
-	type = (pi->pi_ra_flags & ND_RA_FLAG_MANAGED) ? DHCP_START :
-	    DHCP_INFORM;
-
-	request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0,
-	    DHCP_TYPE_NONE);
-	if (request == NULL) {
-		logmsg(LOG_ERR, "start_dhcp: out of memory\n");
-		/* make sure we try again next time there's a chance */
-		pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
-		return;
-	}
+	else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED)
+		type = DHCP_START;
+	else
+		type = DHCP_INFORM;
 
-	error = dhcp_ipc_make_request(request, &reply, 0);
-	free(request);
-	if (error != 0) {
-		logmsg(LOG_ERR, "start_dhcp: err: %s: %s\n", pi->pi_name,
-		    dhcp_ipc_strerror(error));
-		return;
-	}
-
-	error = reply->return_code;
-	free(reply);
-
+	error = dhcp_op(pi, type);
 	/*
 	 * Timeout is considered to be "success" because we don't wait for DHCP
 	 * to do its exchange.
 	 */
 	if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
 	    error != DHCP_IPC_E_TIMEOUT) {
-		logmsg(LOG_ERR, "start_dhcp: ret: %s: %s\n", pi->pi_name,
-		    dhcp_ipc_strerror(error));
-		return;
+		logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
+		    pi->pi_name, dhcp_ipc_strerror(error));
+	}
+}
+
+/*
+ * Release the acquired DHCPv6 lease on a given physical interface.
+ * Does not wait for a message to be returned from the daemon.
+ */
+void
+release_dhcp(struct phyint *pi)
+{
+	int	error;
+	int	type;
+
+	type = DHCP_RELEASE;
+retry:
+	error = dhcp_op(pi, type);
+	if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
+	    error != DHCP_IPC_E_TIMEOUT) {
+		if (type == DHCP_RELEASE && error == DHCP_IPC_E_OUTSTATE) {
+			/*
+			 * Drop the dhcp control if we cannot release it.
+			 */
+			type = DHCP_DROP;
+			goto retry;
+		}
+		logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
+		    pi->pi_name, dhcp_ipc_strerror(error));
 	}
 }
 
@@ -436,7 +478,7 @@
 	 * get addresses via DHCP; only "other" data.  If "managed" is set,
 	 * then we must always get both addresses and "other" data.
 	 */
-	if (pi->pi_StatefulAddrConf &&
+	if (pi->pi_autoconf && pi->pi_stateful &&
 	    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
 	    (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) {
 		if (debug & D_DHCP) {
@@ -540,14 +582,14 @@
 		return;
 	}
 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) &&
-	    pi->pi_StatelessAddrConf) {
+	    pi->pi_stateless && pi->pi_autoconf) {
 		good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback);
 	}
 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
 	    good_prefix) {
 		incoming_prefix_onlink(pi, opt);
 	}
-	if (pi->pi_StatefulAddrConf)
+	if (pi->pi_stateful && pi->pi_autoconf)
 		incoming_prefix_stateful(pi, opt);
 }
 
@@ -924,8 +966,10 @@
 			    "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n",
 			    pbuf, plen, abuf, pi->pi_name, preftime,
 			    pi->pi_TmpRegenAdvance);
-			if (new_prefix)
+			if (new_prefix) {
+				prefix_update_ipadm_addrobj(pr, _B_FALSE);
 				prefix_delete(pr);
+			}
 			return (_B_TRUE);
 		}
 	}
@@ -939,7 +983,7 @@
 		/*
 		 * Form a new local address if the lengths match.
 		 */
-		if (pr->pr_flags && IFF_TEMPORARY) {
+		if (pr->pr_flags & IFF_TEMPORARY) {
 			if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) {
 				if (!tmptoken_create(pi)) {
 					prefix_delete(pr);
@@ -990,6 +1034,7 @@
 			    "Prefix already exists in interface %s\n",
 			    other_pr->pr_physical->pi_name);
 			if (new_prefix) {
+				prefix_update_ipadm_addrobj(pr, _B_FALSE);
 				prefix_delete(pr);
 				return (_B_FALSE);
 			}
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -131,6 +131,10 @@
 	pi->pi_TmpRegenCountdown = TIMER_INFINITY;
 
 	pi->pi_sock = -1;
+	pi->pi_stateless = pi->pi_StatelessAddrConf;
+	pi->pi_stateful = pi->pi_StatefulAddrConf;
+	pi->pi_autoconf = _B_TRUE;
+	pi->pi_default_token = _B_TRUE;
 	if (phyint_init_from_k(pi) == -1) {
 		free(pi);
 		return (NULL);
@@ -237,6 +241,7 @@
 			(void) close(pi->pi_sock);
 			pi->pi_sock = -1;
 		}
+
 		if (debug & D_PHYINT) {
 			logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
 			    "IFF_NOLOCAL or not IFF_UP\n", pi->pi_name);
@@ -258,19 +263,21 @@
 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
 	pi->pi_ifaddr = sin6->sin6_addr;
 
-	if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) {
-		logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN");
-		goto error;
+	if (pi->pi_autoconf && pi->pi_default_token) {
+		if (ioctl(fd, SIOCGLIFTOKEN, (char *)&lifr) < 0) {
+			logperror_pi(pi, "phyint_init_from_k: SIOCGLIFTOKEN");
+			goto error;
+		}
+		/* Ignore interface if the token is all zeros */
+		sin6 = (struct sockaddr_in6 *)&lifr.lifr_token;
+		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+			logmsg(LOG_ERR, "ignoring interface %s: zero token\n",
+			    pi->pi_name);
+			goto error;
+		}
+		pi->pi_token = sin6->sin6_addr;
+		pi->pi_token_length = lifr.lifr_addrlen;
 	}
-	/* Ignore interface if the token is all zeros */
-	sin6 = (struct sockaddr_in6 *)&lifr.lifr_token;
-	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
-		logmsg(LOG_ERR, "ignoring interface %s: zero token\n",
-		    pi->pi_name);
-		goto error;
-	}
-	pi->pi_token = sin6->sin6_addr;
-	pi->pi_token_length = lifr.lifr_addrlen;
 
 	/*
 	 * Guess a remote token for POINTOPOINT by looking at
@@ -472,8 +479,10 @@
 
 	while (pi->pi_router_list)
 		router_delete(pi->pi_router_list);
-	while (pi->pi_prefix_list)
+	while (pi->pi_prefix_list) {
+		prefix_update_ipadm_addrobj(pi->pi_prefix_list, _B_FALSE);
 		prefix_delete(pi->pi_prefix_list);
+	}
 	while (pi->pi_adv_prefix_list)
 		adv_prefix_delete(pi->pi_adv_prefix_list);
 
@@ -1262,6 +1271,12 @@
 				    pr2->pr_name, pr->pr_name);
 			prefix_update_dhcp(pr);
 		}
+		/*
+		 * If this interface was created using ipadm, store the
+		 * addrobj for the DHCPv6 interface in ipmgmtd daemon's
+		 * in-memory aobjmap.
+		 */
+		prefix_update_ipadm_addrobj(pr, _B_TRUE);
 	} else {
 		if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
 			logperror_pr(pr,
@@ -1344,6 +1359,7 @@
  * was added by in.ndpd (i.e. PR_STATIC is not set).
  * Handles delete of things that have not yet been inserted in the list
  * i.e. pr_physical is NULL.
+ * Removes the ipadm addrobj created for the prefix.
  */
 void
 prefix_delete(struct prefix *pr)
@@ -1357,9 +1373,10 @@
 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
 		    abuf, sizeof (abuf)), pr->pr_prefix_len);
 	}
+	pi = pr->pr_physical;
+
 	/* Remove non-static prefixes from the kernel. */
 	pr->pr_state &= PR_STATIC;
-	pi = pr->pr_physical;
 	if (pr->pr_kernel_state != pr->pr_state)
 		prefix_update_k(pr);
 
@@ -1372,6 +1389,7 @@
 	if (pr->pr_next != NULL)
 		pr->pr_next->pr_prev = pr->pr_prev;
 	pr->pr_next = pr->pr_prev = NULL;
+
 	free(pr);
 }
 
@@ -1595,6 +1613,11 @@
 			logperror_pr(pr, "prefix_update_k: SIOCSLIFADDR");
 			return;
 		}
+		/*
+		 * If this interface was created using ipadm, store the
+		 * addrobj for the prefix in ipmgmtd daemon's aobjmap.
+		 */
+		prefix_update_ipadm_addrobj(pr, _B_TRUE);
 		if (pr->pr_state & PR_ONLINK) {
 			sin6->sin6_addr = pr->pr_prefix;
 			lifr.lifr_addrlen = pr->pr_prefix_len;
@@ -2315,4 +2338,55 @@
 	(void) poll_remove(pi->pi_sock);
 	(void) close(pi->pi_sock);
 	pi->pi_sock = -1;
+	pi->pi_stateless = pi->pi_StatelessAddrConf;
+	pi->pi_stateful = pi->pi_StatefulAddrConf;
+	pi->pi_ipadm_aobjname[0] = '\0';
 }
+
+/*
+ * Sets/removes the ipadm address object name for the given prefix.
+ */
+void
+prefix_update_ipadm_addrobj(struct prefix *pr, boolean_t add)
+{
+	struct phyint *pi = pr->pr_physical;
+	int lnum = 0;
+	char *cp;
+	ipadm_handle_t iph;
+	ipadm_status_t status;
+
+	/*
+	 * If ipadm was used to autoconfigure this interface,
+	 * pi_ipadm_aobjname will contain the address object name
+	 * that is used to identify the addresses. Use the same
+	 * address object name for this prefix.
+	 */
+	if (pi->pi_ipadm_aobjname[0] == '\0' ||
+	    pr->pr_name[0] == '\0' || IN6_IS_ADDR_LINKLOCAL(&pr->pr_address) ||
+	    (!(pr->pr_flags & IFF_ADDRCONF) &&
+	    !(pr->pr_flags & IFF_DHCPRUNNING))) {
+		return;
+	}
+	if ((status = ipadm_open(&iph, 0)) != IPADM_SUCCESS) {
+		logmsg(LOG_ERR, "Could not open handle to libipadm: %s\n",
+		    ipadm_status2str(status));
+		return;
+	}
+	cp = strrchr(pr->pr_name, ':');
+	if (cp != NULL)
+		lnum = atoi(++cp);
+	if (add) {
+		status = ipadm_add_aobjname(iph, pi->pi_name, AF_INET6,
+		    pi->pi_ipadm_aobjname, IPADM_ADDR_IPV6_ADDRCONF, lnum);
+	} else {
+		status = ipadm_delete_aobjname(iph, pi->pi_name, AF_INET6,
+		    pi->pi_ipadm_aobjname, IPADM_ADDR_IPV6_ADDRCONF, lnum);
+	}
+	/* Ignore the error if the ipmgmtd daemon is not running */
+	if (status != IPADM_SUCCESS && status != IPADM_IPC_ERROR) {
+		logmsg(LOG_ERR, "ipadm error in %s '%s' : %s\n",
+		    (add ? "adding" : "deleting"), pi->pi_ipadm_aobjname,
+		    ipadm_status2str(status));
+	}
+	ipadm_close(iph);
+}
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,6 +31,7 @@
 #endif
 
 #include <ndpd.h>
+#include <libipadm.h>
 
 enum adv_states { NO_ADV = 0, REG_ADV, INIT_ADV, SOLICIT_ADV, FINAL_ADV };
 enum adv_events { ADV_OFF, START_INIT_ADV, START_FINAL_ADV, RECEIVED_SOLICIT,
@@ -60,6 +61,8 @@
 	uint_t		pi_mtu;			/* From SIOCGLIFMTU */
 	struct in6_addr pi_token;
 	uint_t		pi_token_length;
+	boolean_t	pi_stateless;
+	boolean_t	pi_stateful;
 	struct in6_addr	pi_tmp_token;		/* For RFC3041 addrs */
 	struct in6_addr	pi_dst_token;		/* For POINTOPOINT */
 
@@ -119,9 +122,12 @@
 	 * even if no Router Advertisements are received.
 	 * Tracked using pi_each_time_since_random.
 	 */
-	uint_t		pi_RetransTimer;		/* In milliseconds */
+	uint_t		pi_RetransTimer;	/* In milliseconds */
 
-	uint_t		pi_ra_flags;		/* Detect when to start DHCP */
+	uint_t		pi_ra_flags;	/* Detect when to start DHCP */
+	boolean_t	pi_autoconf;	/* Enable/Disable autoconfiguration */
+	boolean_t	pi_default_token;	/* Use default token */
+	char		pi_ipadm_aobjname[IPADM_AOBJSIZ];
 };
 
 /*
@@ -311,6 +317,7 @@
 extern void	in_data(struct phyint *pi);
 
 extern void	start_dhcp(struct phyint *pi);
+extern void	release_dhcp(struct phyint *pi);
 
 extern void	incoming_ra(struct phyint *pi, struct nd_router_advert *ra,
 		    int len, struct sockaddr_in6 *from, boolean_t loopback);
@@ -323,6 +330,9 @@
 extern void	incoming_prefix_onlink_process(struct prefix *pr,
 		    uchar_t *opt);
 
+extern void	check_autoconf_var_consistency(struct phyint *, boolean_t,
+    boolean_t);
+extern void	prefix_update_ipadm_addrobj(struct prefix *pr, boolean_t add);
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -54,7 +54,7 @@
 CMDPROG=	in.telnetd
 K5PROGS=	in.telnetd in.rlogind in.rshd
 TSNETPROG=	route
-DLADMPROG=	6to4relay ndd
+DLADMPROG=	6to4relay
 DEFAULTFILES=	telnetd.dfl
 
 PROGSRCS=	$(PROG:%=%.c)
@@ -66,12 +66,12 @@
 SRCS=		$(PROGSRCS) $(OTHERSRC)
 
 SUBDIRS=	bootconfchk htable ifconfig ilbadm in.ftpd in.rdisc in.routed \
-		in.talkd inetadm inetconv ipmpstat ipqosconf ipsecutils \
+		in.talkd inetadm inetconv ipadm ipmpstat ipqosconf ipsecutils \
 		kssl/kssladm kssl/ksslcfg nwamadm nwamcfg ping routeadm \
 		snoop sppptun traceroute wificonfig
 
 MSGSUBDIRS=	bootconfchk htable ifconfig ilbadm in.ftpd in.routed in.talkd \
-		inetadm inetconv ipmpstat ipqosconf ipsecutils kssl/ksslcfg \
+		inetadm inetconv ipadm ipmpstat ipqosconf ipsecutils kssl/ksslcfg \
 		nwamadm nwamcfg routeadm sppptun snoop wificonfig
 
 # As programs get lint-clean, add them here and to the 'lint' target.
@@ -151,6 +151,7 @@
 if_mpadm		:=	LDLIBS += -linetutil -lipmp
 if_mpadm.po		:=	XGETFLAGS += -a
 route			:=	CPPFLAGS += -DNDEBUG
+ndd			:=	LDLIBS += -ldladm -lipadm
 gettable in.comsat	:=	LDFLAGS += $(MAPFILE.NGB:%=-M%)
 
 .KEEP_STATE:
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -37,7 +37,7 @@
 SRCS=		$(LOCALSRCS) $(COMMONSRCS)
 
 CPPFLAGS +=	-I$(CMDINETCOMMONDIR) -I$(SRC)/common/net/dhcp
-LDLIBS +=       -ldhcpagent -ldlpi -linetutil -lipmp -ldladm
+LDLIBS +=       -ldhcpagent -ldlpi -linetutil -lipmp -ldladm -lipadm
 LINTFLAGS +=	-m
 
 ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%)
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c	Fri Mar 26 17:53:11 2010 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -18,11 +18,15 @@
 #include <libdllink.h>
 #include <inet/ip.h>
 #include <inet/ipsec_impl.h>
+#include <libipadm.h>
+#include <ifaddrs.h>
+#include <libsocket_priv.h>
 
 #define	LOOPBACK_IF	"lo0"
 #define	NONE_STR	"none"
 #define	ARP_MOD_NAME	"arp"
-#define	IPMPSTUB	(void *)-1
+#define	LIFC_DEFAULT	(LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
+			LIFC_UNDER_IPMP)
 
 typedef struct if_flags {
 	uint64_t iff_value;
@@ -93,8 +97,11 @@
 /* foreach interface saved name */
 static char		origname[LIFNAMSIZ];
 static int		setaddr;
+static boolean_t	setaddr_done = _B_FALSE;
 static boolean_t	ipsec_policy_set;
 static boolean_t	ipsec_auth_covered;
+static ipadm_handle_t	iph;
+static ipadm_addrobj_t	ipaddr;
 
 /*
  * Make sure the algorithm variables hold more than the sizeof an algorithm
@@ -149,7 +156,7 @@
 static int	configinfo(char *arg, int64_t param);
 static void	print_config_flags(int af, uint64_t flags);
 static void	print_flags(uint64_t flags);
-static void	print_ifether(char *ifname);
+static void	print_ifether(const char *ifname);
 static int	set_tun_encap_limit(char *arg, int64_t param);
 static int	clr_tun_encap_limit(char *arg, int64_t param);
 static int	set_tun_hop_limit(char *arg, int64_t param);
@@ -157,6 +164,7 @@
 static int	setallzones(char *arg, int64_t param);
 static int	setifsrc(char *arg, int64_t param);
 static int	lifnum(const char *ifname);
+static void	plumball(int, char **, int64_t, int64_t, int64_t);
 
 /*
  * Address family specific function prototypes.
@@ -172,36 +180,37 @@
  * Misc support functions
  */
 static boolean_t	ni_entry(const char *, void *);
-static void	foreachinterface(void (*func)(), int argc, char *argv[],
-		    int af, int64_t onflags, int64_t offflags,
-		    int64_t lifc_flags);
-static void	ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp);
+static void		foreachinterface(int argc, char *argv[],
+			    int af, int64_t onflags, int64_t offflags,
+			    int64_t lifc_flags);
+static void		ifconfig(int argc, char *argv[], int af,
+			    struct ifaddrs *ifa);
 static boolean_t	in_getmask(struct sockaddr_in *saddr,
 			    boolean_t addr_set);
-static int	in_getprefixlen(char *addr, boolean_t slash, int plen);
+static int		in_getprefixlen(char *addr, boolean_t slash, int plen);
 static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
 			    uchar_t *mask);
-static void	status(void);
-static void	ifstatus(const char *);
-static void	tun_status(datalink_id_t);
-static void	usage(void);
-static int	strioctl(int s, int cmd, void *buf, int buflen);
-static int	setifdhcp(const char *caller, const char *ifname,
-		    int argc, char *argv[]);
-static int	ip_domux2fd(int *, int *, int *, int *, int *);
-static int	ip_plink(int, int, int, int, int);
-static int	modop(char *arg, char op);
-static int	find_all_interfaces(struct lifconf *lifcp, char **buf,
-		    int64_t lifc_flags);
-static int	create_ipmp(const char *grname, int af, const char *ifname,
-		    boolean_t implicit);
-static int	create_ipmp_peer(int af, const char *ifname);
-static void	start_ipmp_daemon(void);
-static boolean_t ifaddr_up(ifaddrlistx_t *ifaddrp);
-static boolean_t ifaddr_down(ifaddrlistx_t *ifaddrp);
+static void		status(void);
+static void		ifstatus(const char *ifname);
+static void		tun_status(datalink_id_t);
+static void		usage(void);
+static int		setifdhcp(const char *caller, const char *ifname,
+			    int argc, char *argv[]);
+static int		ip_domux2fd(int *, int *, int *, int *, int *);
+static int		ip_plink(int, int, int, int, int);
+static int		modop(char *arg, char op);
+static int		find_all_interfaces(struct lifconf *lifcp, char **buf,
+			    int64_t lifc_flags);
+static int		create_ipmp(const char *grname, int af,
+			    const char *ifname, boolean_t implicit);
+static void		start_ipmp_daemon(void);
+static boolean_t 	ifaddr_up(ifaddrlistx_t *ifaddrp);
+static boolean_t 	ifaddr_down(ifaddrlistx_t *ifaddrp);
 static dladm_status_t	ifconfig_dladm_open(const char *, datalink_class_t,
-		    datalink_id_t *);
-static void	dladmerr_exit(dladm_status_t status, const char *str);
+			    datalink_id_t *);
+static void		dladmerr_exit(dladm_status_t status, const char *str);
+static void		ipadmerr_exit(ipadm_status_t status, const char *str);
+static boolean_t	ifconfig_use_libipadm(int, const char *);
 
 #define	max(a, b)	((a) < (b) ? (b) : (a))
 
@@ -366,8 +375,9 @@
 {
 	int64_t		lifc_flags;
 	char		*default_ip_str;
-
-	lifc_flags = LIFC_NOXMIT|LIFC_TEMPORARY|LIFC_ALLZONES|LIFC_UNDER_IPMP;
+	ipadm_status_t	istatus;
+
+	lifc_flags = LIFC_DEFAULT;
 
 	if (argc < 2) {
 		usage();
@@ -412,6 +422,13 @@
 	s6 = socket(AF_INET6, SOCK_DGRAM, 0);
 	if (s == -1 || s4 == -1 || s6 == -1)
 		Perror0_exit("socket");
+	/*
+	 * Open the global libipadm handle. The flag IPH_LEGACY has to
+	 * be specified to indicate that logical interface names will
+	 * be used during interface creation and address creation.
+	 */
+	if ((istatus = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS)
+		ipadmerr_exit(istatus, "unable to open handle to libipadm");
 
 	/*
 	 * Special interface names is any combination of these flags.
@@ -484,157 +501,89 @@
 			    "ifconfig: %s: no such interface\n", name);
 			exit(1);
 		}
-		foreachinterface(ifconfig, argc, argv, af, onflags, offflags,
+		foreachinterface(argc, argv, af, onflags, offflags,
 		    lifc_flags);
 	} else {
-		ifconfig(argc, argv, af, (struct lifreq *)NULL);
+		ifconfig(argc, argv, af, NULL);
 	}
+	ipadm_close(iph);
 	return (0);
 }
 
 /*
- * For each interface, call (*func)(argc, argv, af, lifrp).
+ * For each interface, call ifconfig(argc, argv, af, ifa).
  * Only call function if onflags and offflags are set or clear, respectively,
  * in the interfaces flags field.
  */
 static void
-foreachinterface(void (*func)(), int argc, char *argv[], int af,
+foreachinterface(int argc, char *argv[], int af,
     int64_t onflags, int64_t offflags, int64_t lifc_flags)
 {
-	int n;
-	char *buf;
-	struct lifnum lifn;
-	struct lifconf lifc;
-	struct lifreq *lifrp;
-	struct lifreq lifrl;	/* Local lifreq struct */
-	int numifs;
-	unsigned bufsize;
-	int plumball = 0;
-	int save_af = af;
-
-	buf = NULL;
+	ipadm_addr_info_t *ainfo, *ainfop;
+	struct ifaddrs *ifa;
+	ipadm_status_t istatus;
+
 	/*
 	 * Special case:
 	 * ifconfig -a plumb should find all network interfaces in the current
 	 * zone.
 	 */
 	if (argc > 0 && (strcmp(*argv, "plumb") == 0)) {
-		if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 ||
-		    lifc.lifc_len == 0)
-			return;
-		plumball = 1;
-	} else {
-		lifn.lifn_family = AF_UNSPEC;
-		lifn.lifn_flags = lifc_flags;
-		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
-			Perror0_exit("Could not determine number"
-			    " of interfaces");
+		plumball(argc, argv, onflags, offflags, lifc_flags);
+		return;
+	}
+	/* Get all addresses in kernel including addresses that are zero. */
+	istatus = ipadm_addr_info(iph, NULL, &ainfo, IPADM_OPT_ZEROADDR,
+	    lifc_flags);
+	if (istatus != IPADM_SUCCESS)
+		ipadmerr_exit(istatus, "could not get addresses from kernel");
+
+	/*
+	 * For each logical interface, call ifconfig() with the
+	 * given arguments.
+	 */
+	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
+		if (ainfop->ia_state == IFA_DISABLED)
+			continue;
+		ifa = &ainfop->ia_ifa;
+		if (onflags || offflags) {
+			if ((ifa->ifa_flags & onflags) != onflags)
+				continue;
+			if ((~ifa->ifa_flags & offflags) != offflags)
+				continue;
 		}
-		numifs = lifn.lifn_count;
-		if (debug)
-			(void) printf("ifconfig: %d interfaces\n",  numifs);
-
-		bufsize = numifs * sizeof (struct lifreq);
-		if ((buf = malloc(bufsize)) == NULL) {
-			Perror0("out of memory\n");
-			(void) close(s);
-			return;
-		}
-
-		lifc.lifc_family = AF_UNSPEC;
-		lifc.lifc_flags = lifc_flags;
-		lifc.lifc_len = bufsize;
-		lifc.lifc_buf = buf;
-
-		if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
-			Perror0("SIOCGLIFCONF");
-			(void) close(s);
-			free(buf);
-			return;
-		}
+		s = (ifa->ifa_addr->ss_family == AF_INET ? s4 : s6);
+		(void) strncpy(name, ifa->ifa_name, sizeof (name));
+		(void) strncpy(origname, name, sizeof (origname));
+		ifconfig(argc, argv, af, ifa);
 	}
+	ipadm_free_addr_info(ainfo);
+}
+
+/*
+ * Used for `ifconfig -a plumb'. Finds all datalinks and plumbs the interface.
+ */
+static void
+plumball(int argc, char *argv[], int64_t onflags, int64_t offflags,
+    int64_t lifc_flags)
+{
+	int n;
+	struct lifreq *lifrp;
+	struct lifconf lifc;
+	char *buf;
+
+	if (onflags != 0 || offflags != 0) {
+		(void) fprintf(stderr, "ifconfig: invalid syntax used to "
+		    "plumb all interfaces.\n");
+		exit(1);
+	}
+
+	if (find_all_interfaces(&lifc, &buf, lifc_flags) != 0 ||
+	    lifc.lifc_len == 0)
+		return;
 
 	lifrp = lifc.lifc_req;
 	for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
-
-		if (!plumball) {
-			/*
-			 * We must close and recreate the socket each time
-			 * since we don't know what type of socket it is now
-			 * (each status function may change it).
-			 */
-
-			(void) close(s);
-
-			af = lifrp->lifr_addr.ss_family;
-			s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
-			if (s == -1) {
-				/*
-				 * Perror0() assumes the name to be in the
-				 * globally defined lifreq structure.
-				 */
-				(void) strncpy(lifr.lifr_name,
-				    lifrp->lifr_name, sizeof (lifr.lifr_name));
-				Perror0_exit("socket");
-			}
-		}
-
-		/*
-		 * Only service interfaces that match the on and off
-		 * flags masks.
-		 */
-		if (onflags || offflags) {
-			(void) memset(&lifrl, 0, sizeof (lifrl));
-			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
-			    sizeof (lifrl.lifr_name));
-			if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
-				/*
-				 * Perror0() assumes the name to be in the
-				 * globally defined lifreq structure.
-				 */
-				(void) strncpy(lifr.lifr_name,
-				    lifrp->lifr_name, sizeof (lifr.lifr_name));
-				Perror0_exit("foreachinterface: SIOCGLIFFLAGS");
-			}
-			if ((lifrl.lifr_flags & onflags) != onflags)
-				continue;
-			if ((~lifrl.lifr_flags & offflags) != offflags)
-				continue;
-		}
-
-		if (!plumball) {
-			(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
-			    sizeof (lifrl.lifr_name));
-			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) {
-				/*
-				 * Perror0() assumes the name to be in the
-				 * globally defined lifreq structure.
-				 */
-				(void) strncpy(lifr.lifr_name,
-				    lifrp->lifr_name, sizeof (lifr.lifr_name));
-				Perror0("foreachinterface: SIOCGLIFADDR");
-				continue;
-			}
-			if (lifrl.lifr_addr.ss_family != af) {
-				/* Switch address family */
-				af = lifrl.lifr_addr.ss_family;
-				(void) close(s);
-
-				s = socket(SOCKET_AF(af), SOCK_DGRAM, 0);
-				if (s == -1) {
-					/*
-					 * Perror0() assumes the name to be in
-					 * the globally defined lifreq
-					 * structure.
-					 */
-					(void) strncpy(lifr.lifr_name,
-					    lifrp->lifr_name,
-					    sizeof (lifr.lifr_name));
-					Perror0_exit("socket");
-				}
-			}
-		}
-
 		/*
 		 * Reset global state
 		 * setaddr: Used by parser to tear apart source and dest
@@ -644,24 +593,23 @@
 		setaddr = 0;
 		(void) strncpy(name, lifrp->lifr_name, sizeof (name));
 		(void) strncpy(origname, name, sizeof (origname));
-
-		(*func)(argc, argv, save_af, lifrp);
-		/* the func could have overwritten origname, so restore */
-		(void) strncpy(name, origname, sizeof (name));
+		ifconfig(argc, argv, af, NULL);
 	}
-	if (buf != NULL)
-		free(buf);
 }
 
 /*
- * for the specified interface call (*func)(argc, argv, af, lifrp).
+ * Parses the interface name and the command in argv[]. Calls the
+ * appropriate callback function for the given command from `cmds[]'
+ * table.
+ * If there is no command specified, it prints all addresses.
  */
-
 static void
-ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
+ifconfig(int argc, char *argv[], int af, struct ifaddrs *ifa)
 {
 	static boolean_t scan_netmask = _B_FALSE;
 	int ret;
+	ipadm_status_t istatus;
+	struct lifreq lifr;
 
 	if (argc == 0) {
 		status();
@@ -782,8 +730,52 @@
 		 * else (no keyword found), we assume it's an address
 		 * of some sort
 		 */
-		if (p->c_name == 0 && setaddr)
-			p++;	/* got src, do dst */
+		if (setaddr && ipaddr != NULL) {
+			/*
+			 * We must have already filled in a source address in
+			 * `ipaddr' and we now got a destination address.
+			 * Fill it in `ipaddr' and call libipadm to create
+			 * the static address.
+			 */
+			if (p->c_name == 0) {
+				istatus = ipadm_set_dst_addr(ipaddr, *argv,
+				    (p->c_af == AF_ANY ? AF_UNSPEC : af));
+				if (istatus != IPADM_SUCCESS) {
+					ipadmerr_exit(istatus, "could not "
+					    "set destination address");
+				}
+				/*
+				 * finished processing dstaddr, so reset setaddr
+				 */
+				setaddr = 0;
+			}
+			/*
+			 * Both source and destination address are in `ipaddr'.
+			 * Add the address by calling libipadm.
+			 */
+			istatus = ipadm_create_addr(iph, ipaddr,
+			    IPADM_OPT_ACTIVE);
+			if (istatus != IPADM_SUCCESS)
+				goto createfailed;
+			ipadm_destroy_addrobj(ipaddr);
+			ipaddr = NULL;
+			setaddr_done = _B_TRUE;
+			if (p->c_name == 0) {
+				/* move parser along */
+				argc--, argv++;
+				continue;
+			}
+		}
+		if (p->c_name == 0 && setaddr_done) {
+			/*
+			 * catch odd commands like
+			 * "ifconfig <intf> addr1 addr2 addr3 addr4 up"
+			 */
+			(void) fprintf(stderr, "%s",
+			    "ifconfig: cannot configure more than two "
+			    "addresses in one command\n");
+			exit(1);
+		}
 		if (p->c_func) {
 			if (p->c_af == AF_INET6) {
 				v4compat = 0;
@@ -812,8 +804,8 @@
 			 *		the address families match
 			 */
 			if ((p->c_af == AF_ANY)	||
-			    (lifrp == (struct lifreq *)NULL) ||
-			    (lifrp->lifr_addr.ss_family == p->c_af)) {
+			    (ifa == NULL) ||
+			    (ifa->ifa_addr->ss_family == p->c_af)) {
 				ret = (*p->c_func)(*argv, p->c_parameter);
 				/*
 				 *	If c_func failed and we should
@@ -830,11 +822,36 @@
 		argc--, argv++;
 	}
 
+	if (setaddr && ipaddr != NULL) {
+		/*
+		 * Only the source address was provided, which was already
+		 * set in `ipaddr'. Add the address by calling libipadm.
+		 */
+		istatus = ipadm_create_addr(iph, ipaddr, IPADM_OPT_ACTIVE);
+		if (istatus != IPADM_SUCCESS)
+			goto createfailed;
+		ipadm_destroy_addrobj(ipaddr);
+		ipaddr = NULL;
+		setaddr_done = _B_TRUE;
+	}
+
 	/* Check to see if there's a security hole in the tunnel setup. */
 	if (ipsec_policy_set && !ipsec_auth_covered) {
 		(void) fprintf(stderr, "ifconfig: WARNING: tunnel with only "
 		    "ESP and no authentication.\n");
 	}
+	return;
+
+createfailed:
+	(void) fprintf(stderr, "ifconfig: could not create address:% s\n",
+	    ipadm_status2str(istatus));
+	/* Remove the newly created logical interface. */
+	if (strcmp(name, origname) != 0) {
+		assert(strchr(name, ':') != NULL);
+		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
+		(void) ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr);
+	}
+	exit(1);
 }
 
 /* ARGSUSED */
@@ -902,12 +919,15 @@
 static int
 setifaddr(char *addr, int64_t param)
 {
+	ipadm_status_t istatus;
 	int prefixlen = 0;
+	struct  lifreq lifr1;
 	struct	sockaddr_storage laddr;
 	struct	sockaddr_storage netmask;
 	struct	sockaddr_in6 *sin6;
 	struct	sockaddr_in *sin;
 	struct	sockaddr_storage sav_netmask;
+	char cidraddr[BUFSIZ];
 
 	if (addr[0] == '/')
 		return (setifprefixlen(addr, 0));
@@ -951,13 +971,53 @@
 		g_netmask_set = G_NETMASK_NIL;
 		break;
 	}
+
+	/*
+	 * Check and see if any "netmask" command is used and perform the
+	 * necessary operation.
+	 */
+	set_mask_lifreq(&lifr, &laddr, &netmask);
+
+	/* This check is temporary until libipadm supports IPMP interfaces. */
+	if (ifconfig_use_libipadm(s, name)) {
+		istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name,
+		    &ipaddr);
+		if (istatus != IPADM_SUCCESS)
+			ipadmerr_exit(istatus, "setifaddr");
+
+		if (strchr(addr, '/') == NULL) {
+			/*
+			 * lifr.lifr_addr, which is updated by set_mask_lifreq()
+			 * will contain the right mask to use.
+			 */
+			prefixlen = mask2plen(&lifr.lifr_addr);
+			(void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d",
+			    addr, prefixlen);
+			addr = cidraddr;
+		}
+		istatus = ipadm_set_addr(ipaddr, addr, af);
+		if (istatus != IPADM_SUCCESS)
+			ipadmerr_exit(istatus, "could not set address");
+		/*
+		 * let parser know we got a source.
+		 * Next address, if given, should be dest
+		 */
+		setaddr++;
+
+		/*
+		 * address will be set by the parser after nextarg has
+		 * been scanned
+		 */
+		return (0);
+	}
+
 	/* Tell parser that an address was set */
 	setaddr++;
 	/* save copy of netmask to restore in case of error */
-	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
-	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
+	(void) strncpy(lifr1.lifr_name, name, sizeof (lifr1.lifr_name));
+	if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr1) < 0)
 		Perror0_exit("SIOCGLIFNETMASK");
-	sav_netmask = lifr.lifr_addr;
+	sav_netmask = lifr1.lifr_addr;
 
 	/*
 	 * If setting the address and not the mask, clear any existing mask
@@ -966,7 +1026,8 @@
 	 * using the netmask command), set the mask first, so the address will
 	 * be interpreted correctly.
 	 */
-	set_mask_lifreq(&lifr, &laddr, &netmask);
+	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
+	/* lifr.lifr_addr already contains netmask from set_mask_lifreq() */
 	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
 		Perror0_exit("SIOCSLIFNETMASK");
 
@@ -1567,7 +1628,7 @@
 	if ((hwaddr = _link_aton(addr, &hwaddrlen)) == NULL) {
 		if (hwaddrlen == -1)
 			(void) fprintf(stderr,
-			    "ifconfig: %s: bad address\n", hwaddr);
+			    "ifconfig: bad ethernet address\n");
 		else
 			(void) fprintf(stderr, "ifconfig: malloc() failed\n");
 		exit(1);
@@ -1631,7 +1692,7 @@
  * Print an interface's Ethernet address, if it has one.
  */
 static void
-print_ifether(char *ifname)
+print_ifether(const char *ifname)
 {
 	int fd;
 
@@ -1739,6 +1800,8 @@
 	int prefixlen = 0;
 	struct sockaddr_storage laddr;
 	struct sockaddr_storage mask;
+	ipadm_status_t istatus;
+	char cidraddr[BUFSIZ];
 
 	(void) strncpy(name, origname, sizeof (name));
 
@@ -1818,11 +1881,54 @@
 	 * necessary operation.
 	 */
 	set_mask_lifreq(&lifr, &laddr, &mask);
+
+	/* This check is temporary until libipadm supports IPMP interfaces. */
+	if (ifconfig_use_libipadm(s, name)) {
+		/*
+		 * We added the logical interface above before calling
+		 * ipadm_create_addr(), because, with IPH_LEGACY, we need
+		 * to do an addif for `ifconfig ce0 addif <addr>' but not for
+		 * `ifconfig ce0 <addr>'. libipadm does not have a flag to
+		 * to differentiate between these two cases. To keep it simple,
+		 * we always create the logical interface and pass it to
+		 * libipadm instead of requiring libipadm to addif for some
+		 * cases and not do addif for other cases.
+		 */
+		istatus = ipadm_create_addrobj(IPADM_ADDR_STATIC, name,
+		    &ipaddr);
+		if (istatus != IPADM_SUCCESS)
+			ipadmerr_exit(istatus, "addif");
+
+		if (strchr(str, '/') == NULL) {
+			/*
+			 * lifr.lifr_addr, which is updated by set_mask_lifreq()
+			 * will contain the right mask to use.
+			 */
+			prefixlen = mask2plen(&lifr.lifr_addr);
+			(void) snprintf(cidraddr, sizeof (cidraddr), "%s/%d",
+			    str, prefixlen);
+			str = cidraddr;
+		}
+		istatus = ipadm_set_addr(ipaddr, str, af);
+		if (istatus != IPADM_SUCCESS)
+			ipadmerr_exit(istatus, "could not set address");
+		setaddr++;
+		/*
+		 * address will be set by the parser after nextarg
+		 * has been scanned
+		 */
+		return (0);
+	}
+
 	/*
 	 * Only set the netmask if "netmask" command is used or a prefix is
 	 * provided.
 	 */
 	if (g_netmask_set == G_NETMASK_SET || prefixlen >= 0) {
+		/*
+		 * lifr.lifr_addr already contains netmask from
+		 * set_mask_lifreq().
+		 */
 		if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
 			Perror0_exit("addif: SIOCSLIFNETMASK");
 	}
@@ -1850,6 +1956,8 @@
 removeif(char *str, int64_t param)
 {
 	struct sockaddr_storage laddr;
+	ipadm_status_t istatus;
+	ipadm_addr_info_t *ainfo, *ainfop;
 
 	if (strchr(name, ':') != NULL) {
 		(void) fprintf(stderr,
@@ -1859,8 +1967,43 @@
 	}
 
 	(*afp->af_getaddr)(str, &laddr, NULL);
+
+	/*
+	 * Following check is temporary until libipadm supports
+	 * IPMP interfaces.
+	 */
+	if (!ifconfig_use_libipadm(s, name))
+		goto delete;
+
+	/*
+	 * Get all addresses and search this address among the active
+	 * addresses. If an address object was found, delete using
+	 * ipadm_delete_addr().
+	 */
+	istatus = ipadm_addr_info(iph, name, &ainfo, 0, LIFC_DEFAULT);
+	if (istatus != IPADM_SUCCESS)
+		ipadmerr_exit(istatus, "removeif");
+
+	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop))
+		if (sockaddrcmp(ainfop->ia_ifa.ifa_addr, &laddr))
+			break;
+
+	if (ainfop != NULL && ainfop->ia_aobjname[0] != '\0') {
+		istatus = ipadm_delete_addr(iph, ainfop->ia_aobjname,
+		    IPADM_OPT_ACTIVE);
+		if (istatus != IPADM_SUCCESS)
+			ipadmerr_exit(istatus, "could not delete address");
+		ipadm_free_addr_info(ainfo);
+		return (0);
+	}
+	ipadm_free_addr_info(ainfo);
+
+delete:
+	/*
+	 * An address object for this address was not found in ipadm.
+	 * Delete with SIOCLIFREMOVEIF.
+	 */
 	lifr.lifr_addr = laddr;
-
 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
 	if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
 		if (errno == EBUSY) {
@@ -2202,37 +2345,6 @@
 }
 
 /*
- * Open a stream on /dev/udp{,6}, pop off all undesired modules (note that
- * the user may have configured autopush to add modules above
- * udp), and push the arp module onto the resulting stream.
- * This is used to make IP+ARP be able to atomically track the muxid
- * for the I_PLINKed STREAMS, thus it isn't related to ARP running the ARP
- * protocol.
- */
-static int
-open_arp_on_udp(char *udp_dev_name)
-{
-	int fd;
-
-	if ((fd = open(udp_dev_name, O_RDWR)) == -1) {
-		Perror2("open", udp_dev_name);
-		return (-1);
-	}
-	errno = 0;
-	while (ioctl(fd, I_POP, 0) != -1)
-		;
-	if (errno != EINVAL) {
-		Perror2("pop", udp_dev_name);
-	} else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) {
-		Perror2("arp PUSH", udp_dev_name);
-	} else {
-		return (fd);
-	}
-	(void) close(fd);
-	return (-1);
-}
-
-/*
  * Helper function for mod*() functions.  It gets a fd to the lower IP
  * stream and I_PUNLINK's the lower stream.  It also initializes the
  * global variable lifr.
@@ -2286,7 +2398,7 @@
 	/*
 	 * Use /dev/udp{,6} as the mux to avoid linkcycles.
 	 */
-	if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1)
+	if (ipadm_open_arp_on_udp(udp_dev_name, muxfd) != IPADM_SUCCESS)
 		return (-1);
 
 	if (lifr.lifr_arp_muxid != 0) {
@@ -2636,11 +2748,9 @@
 	 * that any previous selection is cleared.
 	 */
 
-	rval = strcmp(arg, name);
-	if (rval == 0) {
+	if (strchr(arg, ':') != NULL) {
 		(void) fprintf(stderr,
-		    "ifconfig: Cannot specify same interface for usesrc"
-		    " group\n");
+		    "ifconfig: Cannot specify logical interface for usesrc \n");
 		exit(1);
 	}
 
@@ -2805,7 +2915,6 @@
 	(void) putchar('\n');
 }
 
-
 /*
  * Print the status of the interface.  If an address family was
  * specified, show it and it only; otherwise, show them all.
@@ -2850,13 +2959,8 @@
 		(*p->af_status)(1, flags);
 	} else {
 		for (p = afs; p->af_name; p++) {
-			(void) close(s);
-			s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0);
 			/* set global af for use in p->af_status */
 			af = p->af_af;
-			if (s == -1) {
-				Perror0_exit("socket");
-			}
 			(*p->af_status)(0, flags);
 		}
 
@@ -3471,277 +3575,6 @@
 }
 
 /*
- * We need to plink both the arp-device stream and the arp-ip-device stream.
- * However the muxid is stored only in IP. Plumbing 2 streams individually
- * is not atomic, and if ifconfig is killed, the resulting plumbing can
- * be inconsistent. For eg. if only the arp stream is plumbed, we have lost
- * the muxid, and the half-baked plumbing can neither be unplumbed nor
- * replumbed, thus requiring a reboot. To avoid the above the following
- * scheme is used.
- *
- * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams.
- * This is done by pushing arp on to the mux (/dev/udp). ARP adds some
- * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know
- * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs
- * the IP stream first, and unplumbs it last. The kernel (IP) does not
- * allow IP stream to be unplumbed without unplumbing arp stream. Similarly
- * it does not allow arp stream to be plumbed before IP stream is plumbed.
- * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic,
- * and IP uses the info in the I_PLINK message to get the muxid.
- *
- * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use
- *    /dev/udp{,6}.
- * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream
- *    depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp
- *    or /dev/udp6 for SIOCGLIFMUXID and SIOCSLIFMUXID.
- * c. We need to push ARP in order to get the required kernel support for
- *    atomic plumbings. The actual work done by ARP is explained in arp.c
- *    Without pushing ARP, we will still be able to plumb/unplumb. But
- *    it is not atomic, and is supported by the kernel for backward
- *    compatibility for other utilities like atmifconfig etc. In this case
- *    the utility must use SIOCSLIFMUXID.
- */
-static int
-ifplumb(const char *linkname, const char *ifname, boolean_t genppa, int af)
-{
-	int	arp_muxid = -1, ip_muxid;
-	int	mux_fd, ip_fd, arp_fd;
-	int 	retval;
-	char	*udp_dev_name;
-	uint64_t flags;
-	uint_t	dlpi_flags;
-	dlpi_handle_t	dh_arp, dh_ip;
-
-	/*
-	 * Always dlpi_open() with DLPI_NOATTACH because the IP and ARP module
-	 * will do the attach themselves for DLPI style-2 links.
-	 */
-	dlpi_flags = DLPI_NOATTACH;
-
-	/*
-	 * If `linkname' is the special token IPMPSTUB, then this is a request
-	 * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
-	 * pass "ipmpstub0" as `linkname' since an admin *could* have a normal
-	 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
-	 */
-	if (linkname == IPMPSTUB) {
-		linkname = "ipmpstub0";
-		dlpi_flags |= DLPI_DEVONLY;
-	}
-
-	retval = dlpi_open(linkname, &dh_ip, dlpi_flags);
-	if (retval != DLPI_SUCCESS)
-		Perrdlpi_exit("cannot open link", linkname, retval);
-
-	if (debug) {
-		(void) printf("ifconfig: ifplumb: link %s, ifname %s, "
-		    "genppa %u\n", linkname, ifname, genppa);
-	}
-
-	ip_fd = dlpi_fd(dh_ip);
-	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1)
-		Perror2_exit("I_PUSH", IP_MOD_NAME);
-
-	/*
-	 * Prepare to set IFF_IPV4/IFF_IPV6 flags as part of SIOCSLIFNAME.
-	 * (At this point in time the kernel also allows an override of the
-	 * IFF_CANTCHANGE flags.)
-	 */
-	lifr.lifr_name[0] = '\0';
-	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
-		Perror0_exit("ifplumb: SIOCGLIFFLAGS");
-
-	if (af == AF_INET6) {
-		flags = lifr.lifr_flags | IFF_IPV6;
-		flags &= ~(IFF_BROADCAST | IFF_IPV4);
-	} else {
-		flags = lifr.lifr_flags | IFF_IPV4;
-		flags &= ~IFF_IPV6;
-	}
-
-	/*
-	 * Set the interface name.  If we've been asked to generate the PPA,
-	 * then find the lowest available PPA (only currently used for IPMP
-	 * interfaces).  Otherwise, use the interface name as-is.
-	 */
-	if (genppa) {
-		int ppa;
-
-		/*
-		 * We'd like to just set lifr_ppa to UINT_MAX and have the
-		 * kernel pick a PPA.  Unfortunately, that would mishandle
-		 * two cases:
-		 *
-		 *	1. If the PPA is available but the groupname is taken
-		 *	   (e.g., the "ipmp2" IP interface name is available
-		 *	   but the "ipmp2" groupname is taken) then the
-		 *	   auto-assignment by the kernel will fail.
-		 *
-		 *	2. If we're creating (e.g.) an IPv6-only IPMP
-		 *	   interface, and there's already an IPv4-only IPMP
-		 *	   interface, the kernel will allow us to accidentally
-		 *	   reuse the IPv6 IPMP interface name (since
-		 *	   SIOCSLIFNAME uniqueness is per-interface-type).
-		 *	   This will cause administrative confusion.
-		 *
-		 * Thus, we instead take a brute-force approach of checking
-		 * whether the IPv4 or IPv6 name is already in-use before
-		 * attempting the SIOCSLIFNAME.  As per (1) above, the
-		 * SIOCSLIFNAME may still fail, in which case we just proceed
-		 * to the next one.  If this approach becomes too slow, we
-		 * can add a new SIOC* to handle this case in the kernel.
-		 */
-		for (ppa = 0; ppa < UINT_MAX; ppa++) {
-			(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
-			    ifname, ppa);
-
-			if (ioctl(s4, SIOCGLIFFLAGS, &lifr) != -1 ||
-			    errno != ENXIO)
-				continue;
-
-			if (ioctl(s6, SIOCGLIFFLAGS, &lifr) != -1 ||
-			    errno != ENXIO)
-				continue;
-
-			lifr.lifr_ppa = ppa;
-			lifr.lifr_flags = flags;
-			retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr);
-			if (retval != -1 || errno != EEXIST)
-				break;
-		}
-	} else {
-		ifspec_t ifsp;
-
-		/*
-		 * The interface name could have come from the command-line;
-		 * check it.
-		 */
-		if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
-			Perror2_exit("invalid IP interface name", ifname);
-
-		/*
-		 * Before we call SIOCSLIFNAME, ensure that the IPMP group
-		 * interface for this address family exists.  Otherwise, the
-		 * kernel will kick the interface out of the group when we do
-		 * the SIOCSLIFNAME.
-		 *
-		 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
-		 * If we're now plumbing bge0 for IPv6, but the IPMP group
-		 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
-		 * will kick bge0 out of group "a", which is undesired.
-		 */
-		if (create_ipmp_peer(af, ifname) == -1) {
-			(void) fprintf(stderr, "ifconfig: warning: cannot "
-			    "create %s IPMP group; %s will be removed from "
-			    "group\n", af == AF_INET ? "IPv4" : "IPv6", ifname);
-		}
-
-		lifr.lifr_ppa = ifsp.ifsp_ppa;
-		lifr.lifr_flags = flags;
-		(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
-		retval = ioctl(ip_fd, SIOCSLIFNAME, &lifr);
-	}
-
-	if (retval == -1) {
-		if (errno != EEXIST)
-			Perror0_exit("SIOCSLIFNAME for ip");
-		/*
-		 * This difference between the way we behave for EEXIST
-		 * and that with other errors exists to preserve legacy
-		 * behaviour. Earlier when foreachinterface() and matchif()
-		 * were doing the duplicate interface name checks, for
-		 * already existing interfaces, inetplumb() returned "0".
-		 * To preserve this behaviour, Perror0() and return are
-		 * called for EEXIST.
-		 */
-		Perror0("SIOCSLIFNAME for ip");
-		return (-1);
-	}
-
-	/* Get the full set of existing flags for this stream */
-	if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1)
-		Perror0_exit("ifplumb: SIOCGLIFFLAGS");
-
-	if (debug) {
-		(void) printf("ifconfig: ifplumb: %s got flags:\n",
-		    lifr.lifr_name);
-		print_flags(lifr.lifr_flags);
-		(void) putchar('\n');
-	}
-
-	/*
-	 * Open "/dev/udp" for use as a multiplexor to PLINK the
-	 * interface stream under. We use "/dev/udp" instead of "/dev/ip"
-	 * since STREAMS will not let you PLINK a driver under itself,
-	 * and "/dev/ip" is typically the driver at the bottom of
-	 * the stream for tunneling interfaces.
-	 */
-	if (af == AF_INET6)
-		udp_dev_name = UDP6_DEV_NAME;
-	else
-		udp_dev_name = UDP_DEV_NAME;
-	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
-		exit(EXIT_FAILURE);
-
-	/* Check if arp is not needed */
-	if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) {
-		/*
-		 * PLINK the interface stream so that ifconfig can exit
-		 * without tearing down the stream.
-		 */
-		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
-			Perror0_exit("I_PLINK for ip");
-		(void) close(mux_fd);
-		return (lifr.lifr_ppa);
-	}
-
-	/*
-	 * This interface does use ARP, so set up a separate stream
-	 * from the interface to ARP.
-	 */
-	if (debug)
-		(void) printf("ifconfig: ifplumb: interface %s", ifname);
-
-	retval = dlpi_open(linkname, &dh_arp, dlpi_flags);
-	if (retval != DLPI_SUCCESS)
-		Perrdlpi_exit("cannot open link", linkname, retval);
-
-	arp_fd = dlpi_fd(dh_arp);
-	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1)
-		Perror2_exit("I_PUSH", ARP_MOD_NAME);
-
-	/*
-	 * Tell ARP the name and unit number for this interface.
-	 * Note that arp has no support for transparent ioctls.
-	 */
-	if (strioctl(arp_fd, SIOCSLIFNAME, &lifr, sizeof (lifr)) == -1) {
-		if (errno != EEXIST)
-			Perror0_exit("SIOCSLIFNAME for arp");
-		Perror0("SIOCSLIFNAME for arp");
-		goto out;
-	}
-
-	/*
-	 * PLINK the IP and ARP streams so that ifconfig can exit
-	 * without tearing down the stream.
-	 */
-	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
-		Perror0_exit("I_PLINK for ip");
-	if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) {
-		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
-		Perror0_exit("I_PLINK for arp");
-	}
-
-	if (debug)
-		(void) printf("arp muxid = %d\n", arp_muxid);
-out:
-	dlpi_close(dh_ip);
-	dlpi_close(dh_arp);
-	(void) close(mux_fd);
-	return (lifr.lifr_ppa);
-}
-
-/*
  * If this is a physical interface then remove it.
  * If it is a logical interface name use SIOCLIFREMOVEIF to
  * remove it. In both cases fail if it doesn't exist.
@@ -3750,245 +3583,36 @@
 static int
 inetunplumb(char *arg, int64_t param)
 {
-	int ip_muxid, arp_muxid;
-	int mux_fd;
-	int muxid_fd;
-	char *udp_dev_name;
-	char *strptr;
-	uint64_t flags;
-	boolean_t changed_arp_muxid = _B_FALSE;
-	int save_errno;
-	boolean_t v6 = (afp->af_af == AF_INET6);
-
-	strptr = strchr(name, ':');
-	if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) {
-		/* Can't unplumb logical interface zero */
-		if (strptr != NULL && strcmp(strptr, ":0") == 0) {
-			(void) fprintf(stderr, "ifconfig: unplumb:"
-			    " Cannot unplumb %s: Invalid interface\n", name);
-			exit(1);
-		}
-		(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
-		(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
-
-		if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
-			Perror0_exit("unplumb: SIOCLIFREMOVEIF");
-		return (0);
-	}
-
-	/*
-	 * We used /dev/udp or udp6 to set up the mux. So we have to use
-	 * the same now for PUNLINK also.
-	 */
-	if (v6)
-		udp_dev_name = UDP6_DEV_NAME;
-	else
-		udp_dev_name = UDP_DEV_NAME;
-
-	if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1)
-		exit(EXIT_FAILURE);
-
-	if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1)
-		exit(EXIT_FAILURE);
-
-	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
-	if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
-		Perror0_exit("unplumb: SIOCGLIFFLAGS");
+	ipadm_status_t	istatus;
+
+	istatus = ipadm_delete_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE);
+	if (istatus != IPADM_SUCCESS) {
+		(void) fprintf(stderr, "ifconfig: cannot unplumb %s: %s\n",
+		    name, ipadm_status2str(istatus));
+		exit(1);
 	}
-	flags = lifr.lifr_flags;
-again:
-	if (flags & IFF_IPMP) {
-		lifgroupinfo_t lifgr;
-		ifaddrlistx_t *ifaddrs, *ifaddrp;
-
-		/*
-		 * There are two reasons the I_PUNLINK can fail with EBUSY:
-		 * (1) if IP interfaces are in the group, or (2) if IPMP data
-		 * addresses are administratively up.  For case (1), we fail
-		 * here with a specific error message.  For case (2), we bring
-		 * down the addresses prior to doing the I_PUNLINK.  If the
-		 * I_PUNLINK still fails with EBUSY then the configuration
-		 * must have changed after our checks, in which case we branch
-		 * back up to `again' and rerun this logic.  The net effect is
-		 * that unplumbing an IPMP interface will only fail with EBUSY
-		 * if IP interfaces are in the group.
-		 */
-		if (ioctl(s, SIOCGLIFGROUPNAME, &lifr) == -1)
-			Perror0_exit("unplumb: SIOCGLIFGROUPNAME");
-
-		(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
-		    LIFGRNAMSIZ);
-		if (ioctl(s, SIOCGLIFGROUPINFO, &lifgr) == -1)
-			Perror0_exit("unplumb: SIOCGLIFGROUPINFO");
-
-		if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
-			(void) fprintf(stderr, "ifconfig: %s: cannot unplumb:"
-			    " IPMP group is not empty\n", name);
-			exit(1);
-		}
-
-		/*
-		 * The kernel will fail the I_PUNLINK if the IPMP interface
-		 * has administratively up addresses; bring 'em down.
-		 */
-		if (ifaddrlistx(name, IFF_UP|IFF_DUPLICATE, 0, &ifaddrs) == -1)
-			Perror2_exit(name, "cannot get address list");
-
-		ifaddrp = ifaddrs;
-		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
-			if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
-			    (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
-				continue;
-
-			if (!ifaddr_down(ifaddrp)) {
-				Perror2_exit(ifaddrp->ia_name,
-				    "cannot bring down");
-			}
-		}
-		ifaddrlistx_free(ifaddrs);
-	}
-
-	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
-		Perror0_exit("unplumb: SIOCGLIFMUXID");
-	}
-	arp_muxid = lifr.lifr_arp_muxid;
-	ip_muxid = lifr.lifr_ip_muxid;
-	/*
-	 * We don't have a good way of knowing whether the arp stream is
-	 * plumbed. We can't rely on IFF_NOARP because someone could
-	 * have turned it off later using "ifconfig xxx -arp".
-	 */
-	if (arp_muxid != 0) {
-		if (debug)
-			(void) printf("arp_muxid %d\n", arp_muxid);
-		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
-			/*
-			 * See the comment before the SIOCGLIFGROUPNAME call.
-			 */
-			if (errno == EBUSY && (flags & IFF_IPMP))
-				goto again;
-
-			if ((errno == EINVAL) &&
-			    (flags & (IFF_NOARP | IFF_IPV6))) {
-				/*
-				 * Some plumbing utilities set the muxid to
-				 * -1 or some invalid value to signify that
-				 * there is no arp stream. Set the muxid to 0
-				 * before trying to unplumb the IP stream.
-				 * IP does not allow the IP stream to be
-				 * unplumbed if it sees a non-null arp muxid,
-				 * for consistency of IP-ARP streams.
-				 */
-				lifr.lifr_arp_muxid = 0;
-				(void) ioctl(muxid_fd, SIOCSLIFMUXID,
-				    (caddr_t)&lifr);
-				changed_arp_muxid = _B_TRUE;
-			} else {
-				Perror0("I_PUNLINK for arp");
-			}
-		}
-	}
-	if (debug)
-		(void) printf("ip_muxid %d\n", ip_muxid);
-
-	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
-		if (changed_arp_muxid) {
-			/*
-			 * Some error occurred, and we need to restore
-			 * everything back to what it was.
-			 */
-			save_errno = errno;
-			lifr.lifr_arp_muxid = arp_muxid;
-			lifr.lifr_ip_muxid = ip_muxid;
-			(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
-			errno = save_errno;
-		}
-
-		/*
-		 * See the comment before the SIOCGLIFGROUPNAME call.
-		 */
-		if (errno == EBUSY && (flags & IFF_IPMP))
-			goto again;
-
-		Perror0_exit("I_PUNLINK for ip");
-	}
-	(void) close(mux_fd);
-	(void) close(muxid_fd);
+
 	return (0);
 }
 
 /*
- * If this is a physical interface then create it unless it is already
- * present. If it is a logical interface name use SIOCLIFADDIF to
- * create and (and fail it if already exists.)
- * As a special case send SIOCLIFADDIF for the loopback interface. This
- * is needed since there is no other notion of plumbing the loopback
- * interface.
+ * Create the interface in `name', using ipadm_create_if(). If `name' is a
+ * logical interface or loopback interface, ipadm_create_if() uses
+ * SIOCLIFADDIF to create it.
  */
 /* ARGSUSED */
 static int
 inetplumb(char *arg, int64_t param)
 {
-	char		*strptr;
-	boolean_t	islo;
-	zoneid_t	zoneid;
-	datalink_id_t	linkid;
-
-	strptr = strchr(name, ':');
-	islo = (strcmp(name, LOOPBACK_IF) == 0);
-
-	if (strptr != NULL || islo) {
-		(void) memset(&lifr, 0, sizeof (lifr));
-		(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
-		if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) {
-			if (debug) {
-				(void) fprintf(stderr,
-				    "ifconfig: %s already exists\n", name);
-			}
-			return (0);
-		}
-		if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
-			if (errno == EEXIST) {
-				if (debug) {
-					(void) fprintf(stderr,
-					    "ifconfig: %s already exists\n",
-					    name);
-				}
-			} else {
-				Perror2_exit("plumb: SIOCLIFADDIF", name);
-			}
-		}
-		return (0);
+	ipadm_status_t	istatus;
+
+	istatus = ipadm_create_if(iph, name, afp->af_af, IPADM_OPT_ACTIVE);
+	if (istatus != IPADM_SUCCESS) {
+		(void) fprintf(stderr, "ifconfig: cannot plumb %s: %s\n",
+		    name, ipadm_status2str(istatus));
+		if (istatus != IPADM_IF_EXISTS)
+			exit(1);
 	}
-
-	/*
-	 * If we're in the global zone and we're plumbing a datalink, make
-	 * sure that the datalink is not assigned to a non-global zone.  Note
-	 * that the non-global zones don't need this check, because zoneadm
-	 * has taken care of this when the zones boot.
-	 */
-	zoneid = getzoneid();
-	if (zoneid == GLOBAL_ZONEID &&
-	    ifconfig_dladm_open(name, DATALINK_CLASS_ALL, &linkid) ==
-	    DLADM_STATUS_OK) {
-		int ret;
-
-		zoneid = ALL_ZONES;
-		ret = zone_check_datalink(&zoneid, linkid);
-		if (ret == 0) {
-			char zonename[ZONENAME_MAX];
-
-			(void) getzonenamebyid(zoneid, zonename, ZONENAME_MAX);
-			(void) fprintf(stderr, "%s is used by non-global"
-			    "zone: %s\n", name, zonename);
-			return (1);
-		}
-	}
-
-	if (debug)
-		(void) printf("inetplumb: %s af %d\n", name, afp->af_af);
-
-	(void) ifplumb(name, name, _B_FALSE, afp->af_af);
 	return (0);
 }
 
@@ -4026,29 +3650,30 @@
 static int
 create_ipmp(const char *grname, int af, const char *ifname, boolean_t implicit)
 {
-	int ppa;
 	static int ipmp_daemon_started;
+	uint32_t flags = IPADM_OPT_IPMP|IPADM_OPT_ACTIVE;
+	ipadm_status_t istatus;
 
 	if (debug) {
 		(void) printf("create_ipmp: ifname %s grname %s af %d\n",
 		    ifname != NULL ? ifname : "NULL", grname, af);
 	}
 
-	if (ifname != NULL)
-		ppa = ifplumb(IPMPSTUB, ifname, _B_FALSE, af);
-	else
-		ppa = ifplumb(IPMPSTUB, "ipmp", _B_TRUE, af);
-
-	if (ppa == -1) {
-		Perror2(grname, "cannot create IPMP interface");
+	/*
+	 * ipadm_create_if() creates the IPMP interface and fills in the
+	 * ppa in lifr.lifr_name, if `ifname'="ipmp".
+	 */
+	(void) strlcpy(lifr.lifr_name, (ifname ? ifname : "ipmp"),
+	    sizeof (lifr.lifr_name));
+	if (ifname == NULL)
+		flags |= IPADM_OPT_GENPPA;
+	istatus = ipadm_create_if(iph, lifr.lifr_name, af, flags);
+	if (istatus != IPADM_SUCCESS) {
+		(void) fprintf(stderr, "ifconfig: cannot create IPMP interface "
+		    "%s: %s\n", grname, ipadm_status2str(istatus));
 		return (-1);
 	}
 
-	if (ifname != NULL)
-		(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
-	else
-		(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "ipmp%d", ppa);
-
 	/*
 	 * To preserve backward-compatibility, always bring up the link-local
 	 * address for implicitly-created IPv6 IPMP interfaces.
@@ -4082,42 +3707,6 @@
 }
 
 /*
- * Check if `ifname' is plumbed and in an IPMP group on its "other" address
- * family.  If so, create a matching IPMP group for address family `af'.
- */
-static int
-create_ipmp_peer(int af, const char *ifname)
-{
-	int		fd;
-	lifgroupinfo_t	lifgr;
-
-	assert(af == AF_INET || af == AF_INET6);
-
-	/*
-	 * Get the socket for the "other" address family.
-	 */
-	fd = (af == AF_INET) ? s6 : s4;
-
-	(void) strlcpy(lifr.lifr_name, ifname, LIFNAMSIZ);
-	if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) != 0)
-		return (0);
-
-	(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
-	if (ioctl(fd, SIOCGLIFGROUPINFO, &lifgr) != 0)
-		return (0);
-
-	/*
-	 * If `ifname' *is* the IPMP group interface, or if the relevant
-	 * address family is already configured, then there's nothing to do.
-	 */
-	if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
-	    (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6))
-		return (0);
-
-	return (create_ipmp(lifgr.gi_grname, af, lifgr.gi_grifname, _B_TRUE));
-}
-
-/*
  * Start in.mpathd if it's not already running.
  */
 static void
@@ -4244,7 +3833,35 @@
 	return (status);
 }
 
-void
+/*
+ * This function checks if we can use libipadm API's. We will only
+ * call libipadm functions for non-IPMP interfaces. This check is
+ * temporary until libipadm supports IPMP interfaces.
+ */
+static boolean_t
+ifconfig_use_libipadm(int s, const char *lifname)
+{
+	struct lifreq lifr1;
+
+	(void) strlcpy(lifr1.lifr_name, lifname, sizeof (lifr1.lifr_name));
+	if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr1) < 0) {
+		(void) strncpy(lifr.lifr_name, lifname,
+		    sizeof (lifr.lifr_name));
+		Perror0_exit("error");
+	}
+
+	return (lifr1.lifr_groupname[0] == '\0');
+}
+
+static void
+ipadmerr_exit(ipadm_status_t status, const char *str)
+{
+	(void) fprintf(stderr, "ifconfig: %s: %s\n", str,
+	    ipadm_status2str(status));
+	exit(1);
+}
+
+static void
 dladmerr_exit(dladm_status_t status, const char *str)
 {
 	char errstr[DLADM_STRSIZE];
@@ -4589,19 +4206,6 @@
 		return (atoi(cp + 1));
 }
 
-static int
-strioctl(int s, int cmd, void *buf, int buflen)
-{
-	struct strioctl ioc;
-
-	(void) memset(&ioc, 0, sizeof (ioc));
-	ioc.ic_cmd = cmd;
-	ioc.ic_timout = 0;
-	ioc.ic_len = buflen;
-	ioc.ic_dp = buf;
-	return (ioctl(s, I_STR, (char *)&ioc));
-}
-
 static void
 add_ni(const char *name)
 {
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h	Fri Mar 26 17:53:11 2010 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -23,9 +23,6 @@
 #define	BAD_ADDR	-1	/* prefix is invalid */
 #define	NO_PREFIX	-2	/* no prefix was found */
 
-/* No suitable header file defines this, though it's in libsocket */
-extern int	getnetmaskbyaddr(struct in_addr, struct in_addr *);
-
 extern int	debug;
 
 extern void	Perror0(const char *);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,94 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+PROG =		ipadm
+ROOTFS_PROG =	$(PROG)
+LOCALOBJS=	ipadm.o
+COMMONOBJS=	
+OBJS=		$(LOCALOBJS) $(COMMONOBJS)
+
+include ../../../Makefile.cmd
+include ../../Makefile.cmd-inet
+
+XGETFLAGS += 	-a -x $(PROG).xcl
+LOCALSRCS=	$(LOCALOBJS:%.o=%.c)
+COMMONSRCS=	$(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c)
+SRCS=		$(LOCALSRCS) $(COMMONSRCS)
+
+CPPFLAGS +=	-I$(CMDINETCOMMONDIR)
+LDLIBS +=       -linetutil -lipadm -lnvpair
+LINTFLAGS +=	-m
+
+ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%)
+
+# ipadm uses the ancillary data feature which is available only through
+# UNIX 98 standards version of Socket interface. This interface is supposed to
+# be accessed by -lxnet. In addition -lsocket is used to capture new
+# not-yet-standard interfaces. Someday -lxnet alone should be enough when IPv6
+# inspired new interfaces are part of standards.
+LDLIBS +=	-lxnet -lsocket
+
+# these #defines are required to use UNIX 98 interfaces
+_D_UNIX98_EXTN= -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
+
+$(OBJS)		:= CPPFLAGS +=	$(_D_UNIX98_EXTN)
+
+LINTFLAGS +=	$(_D_UNIX98_EXTN)
+
+$(ROOTCFGDIR)/ipadm.conf := FILEMODE= 644
+
+#
+# Instrument ipadm with CTF data to ease debugging.
+#
+CTFCONVERT_HOOK = && $(CTFCONVERT_O)
+CTFMERGE_HOOK = && $(CTFMERGE) -L VERSION -o $@ $(OBJS)
+$(OBJS) := CFLAGS += $(CTF_FLAGS)
+
+.KEEP_STATE:
+
+all:	$(ROOTFS_PROG)
+
+$(PROG):	$(OBJS)
+	$(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE_HOOK)
+	$(POST_PROCESS)
+
+install: all $(ROOTSBINPROG) $(ROOTCFGDIR) $(ROOTCFGFILES) $(ROOTUSRSBINLINKS)
+
+$(ROOTUSRSBINLINKS):
+	-$(RM) $@; $(SYMLINK) ../../sbin/$(@F) $@
+
+clean:
+	$(RM) $(OBJS)
+
+lint:	lint_SRCS
+
+$(ROOTCFGDIR):
+	$(INS.dir)
+
+$(ROOTCFGDIR)/%: $(ROOTCFGDIR) %
+	$(INS.file)
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,2198 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <inet/ip.h>
+#include <inet/iptun.h>
+#include <inet/tunables.h>
+#include <libdladm.h>
+#include <libdliptun.h>
+#include <libdllink.h>
+#include <libinetutil.h>
+#include <libipadm.h>
+#include <locale.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <ofmt.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <zone.h>
+
+#define	STR_UNKNOWN_VAL	"?"
+#define	LIFC_DEFAULT	(LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES |\
+			LIFC_UNDER_IPMP)
+
+typedef void cmdfunc_t(int, char **, const char *);
+static cmdfunc_t do_create_if, do_delete_if, do_enable_if, do_disable_if;
+static cmdfunc_t do_show_if;
+static cmdfunc_t do_set_prop, do_show_prop, do_init_prop, do_set_ifprop;
+static cmdfunc_t do_show_ifprop, do_reset_ifprop, do_reset_prop;
+static cmdfunc_t do_show_addrprop, do_set_addrprop, do_reset_addrprop;
+static cmdfunc_t do_create_addr, do_delete_addr, do_show_addr;
+static cmdfunc_t do_enable_addr, do_disable_addr;
+static cmdfunc_t do_up_addr, do_down_addr, do_refresh_addr;
+
+typedef struct	cmd {
+	char		*c_name;
+	cmdfunc_t	*c_fn;
+	const char	*c_usage;
+} cmd_t;
+
+static cmd_t	cmds[] = {
+	/* interface management related sub-commands */
+	{ "create-if",	do_create_if,	"\tcreate-if\t[-t] <interface>"	},
+	{ "disable-if",	do_disable_if,	"\tdisable-if\t-t <interface>"	},
+	{ "enable-if",	do_enable_if,	"\tenable-if\t-t <interface>"	},
+	{ "delete-if",	do_delete_if,	"\tdelete-if\t<interface>"	},
+	{ "show-if",	do_show_if,
+	    "\tshow-if\t\t[[-p] -o <field>,...] [<interface>]\n"	},
+	{ "set-ifprop",	do_set_ifprop,
+	    "\tset-ifprop\t[-t] -p <prop>=<value[,...]> -m <protocol> "
+	    "<interface>" 						},
+	{ "reset-ifprop", do_reset_ifprop,
+	    "\treset-ifprop\t[-t] -p <prop> -m <protocol> <interface>"	},
+	{ "show-ifprop", do_show_ifprop,
+	    "\tshow-ifprop\t[[-c] -o <field>,...] [-p <prop>,...]\n"
+	    "\t\t\t[-m <protocol>] [interface]\n" 			},
+
+	/* address management related sub-commands */
+	{ "create-addr", do_create_addr,
+	    "\tcreate-addr\t[-t] {-T static <static_args> |"
+	    " -T dhcp <dhcp_args> |\n"
+	    "\t\t\t-T addrconf <addrconf_args>} <addrobj>\n"
+	    "\t\t\tstatic_args = <[-d] -a {local|remote}=addr[/prefixlen]>\n"
+	    "\t\t\tdhcp_args = <[-w <seconds> | forever]>\n"
+	    "\t\t\taddrconf_args = <[-i interface-id]\n"
+	    "\t\t\t\t\t[-p {stateful|stateless}={yes|no}]>" 		},
+	{ "down-addr",	do_down_addr,	"\tdown-addr\t[-t] <addrobj>"	},
+	{ "up-addr",	do_up_addr,	"\tup-addr\t\t[-t] <addrobj>"	},
+	{ "disable-addr", do_disable_addr, "\tdisable-addr\t-t <addrobj>" },
+	{ "enable-addr", do_enable_addr, "\tenable-addr\t-t <addrobj>"	},
+	{ "refresh-addr", do_refresh_addr, "\trefresh-addr\t[-i] <addrobj>" },
+	{ "delete-addr", do_delete_addr, "\tdelete-addr\t[-r] <addrobj>" },
+	{ "show-addr",	do_show_addr,
+	    "\tshow-addr\t[[-p] -o <field>,...] [<addrobj>]\n"		},
+	{ "set-addrprop", do_set_addrprop,
+	    "\tset-addrprop\t[-t] -p <prop>=<value[,...]> <addrobj>"	},
+	{ "reset-addrprop", do_reset_addrprop,
+	    "\treset-addrprop\t[-t] -p <prop> <addrobj>"		},
+	{ "show-addrprop", do_show_addrprop,
+	    "\tshow-addrprop\t[[-c] -o <field>,...] [-p <prop>,...] "
+	    "<addrobj>\n" 						},
+
+	/* protocol properties related sub-commands */
+	{ "set-prop",	do_set_prop,
+	    "\tset-prop\t[-t] -p <prop>[+|-]=<value[,...]> <protocol>"	},
+	{ "reset-prop",	do_reset_prop,
+	    "\treset-prop\t[-t] -p <prop> <protocol>"			},
+	{ "show-prop",	do_show_prop,
+	    "\tshow-prop\t[[-c] -o <field>,...] [-p <prop>,...]"
+	    " [protocol]"						},
+
+	/* private sub-commands */
+	{ "init-prop",	do_init_prop, "\tinit-prop\n"			}
+};
+
+static const struct option if_longopts[] = {
+	{"temporary",	no_argument,		0, 't'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option show_prop_longopts[] = {
+	{"parsable",	no_argument,		0, 'c'	},
+	{"prop",	required_argument,	0, 'p'	},
+	{"output",	required_argument,	0, 'o'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option show_ifprop_longopts[] = {
+	{"module",	required_argument,	0, 'm'	},
+	{"parsable",	no_argument,		0, 'c'	},
+	{"prop",	required_argument,	0, 'p'	},
+	{"output",	required_argument,	0, 'o'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option set_prop_longopts[] = {
+	{"prop",	required_argument,	0, 'p'	},
+	{"temporary",	no_argument,		0, 't'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option set_ifprop_longopts[] = {
+	{"module",	required_argument,	0, 'm'	},
+	{"prop",	required_argument,	0, 'p'	},
+	{"temporary",	no_argument,		0, 't'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option addr_misc_longopts[] = {
+	{"inform",	no_argument,		0, 'i'	},
+	{"release",	no_argument,		0, 'r'	},
+	{"temporary",	no_argument,		0, 't'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option addr_longopts[] = {
+	{"address",	required_argument,	0, 'a'	},
+	{"down",	no_argument,		0, 'd'	},
+	{"interface-id", required_argument,	0, 'i'	},
+	{"prop",	required_argument,	0, 'p'	},
+	{"temporary",	no_argument,		0, 't'	},
+	{"type",	required_argument,	0, 'T'	},
+	{"wait",	required_argument,	0, 'w'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option show_addr_longopts[] = {
+	{"parsable",	no_argument,		0, 'p'	},
+	{"output",	required_argument,	0, 'o'	},
+	{ 0, 0, 0, 0 }
+};
+
+static const struct option show_if_longopts[] = {
+	{"parsable",	no_argument,		0, 'p'	},
+	{"output",	required_argument,	0, 'o'	},
+	{ 0, 0, 0, 0 }
+};
+
+/* callback functions to print show-* subcommands output */
+static ofmt_cb_t print_prop_cb;
+static ofmt_cb_t print_sa_cb;
+static ofmt_cb_t print_si_cb;
+
+/* structures for 'ipadm show-*' subcommands */
+typedef enum {
+	IPADM_PROPFIELD_IFNAME,
+	IPADM_PROPFIELD_PROTO,
+	IPADM_PROPFIELD_ADDROBJ,
+	IPADM_PROPFIELD_PROPERTY,
+	IPADM_PROPFIELD_PERM,
+	IPADM_PROPFIELD_CURRENT,
+	IPADM_PROPFIELD_PERSISTENT,
+	IPADM_PROPFIELD_DEFAULT,
+	IPADM_PROPFIELD_POSSIBLE
+} ipadm_propfield_index_t;
+
+static ofmt_field_t intfprop_fields[] = {
+/* name,	field width,	index,			callback */
+{ "IFNAME",	12,	IPADM_PROPFIELD_IFNAME,		print_prop_cb},
+{ "PROPERTY",	16,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
+{ "PROTO",	6,	IPADM_PROPFIELD_PROTO,		print_prop_cb},
+{ "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
+{ "CURRENT",	11,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
+{ "PERSISTENT",	11,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
+{ "DEFAULT",	11,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
+{ "POSSIBLE",	16,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
+{ NULL,		0,	0,				NULL}
+};
+
+
+static ofmt_field_t modprop_fields[] = {
+/* name,	field width,	index,			callback */
+{ "PROTO",	6,	IPADM_PROPFIELD_PROTO,		print_prop_cb},
+{ "PROPERTY",	22,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
+{ "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
+{ "CURRENT",	13,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
+{ "PERSISTENT",	13,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
+{ "DEFAULT",	13,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
+{ "POSSIBLE",	15,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
+{ NULL,		0,	0,				NULL}
+};
+
+static ofmt_field_t addrprop_fields[] = {
+/* name,	field width,	index,			callback */
+{ "ADDROBJ",	18,	IPADM_PROPFIELD_ADDROBJ,	print_prop_cb},
+{ "PROPERTY",	11,	IPADM_PROPFIELD_PROPERTY,	print_prop_cb},
+{ "PERM",	5,	IPADM_PROPFIELD_PERM,		print_prop_cb},
+{ "CURRENT",	16,	IPADM_PROPFIELD_CURRENT,	print_prop_cb},
+{ "PERSISTENT",	16,	IPADM_PROPFIELD_PERSISTENT,	print_prop_cb},
+{ "DEFAULT",	16,	IPADM_PROPFIELD_DEFAULT,	print_prop_cb},
+{ "POSSIBLE",	15,	IPADM_PROPFIELD_POSSIBLE,	print_prop_cb},
+{ NULL,		0,	0,				NULL}
+};
+
+typedef struct show_prop_state {
+	char		sps_ifname[LIFNAMSIZ];
+	char		sps_aobjname[IPADM_AOBJSIZ];
+	const char	*sps_pname;
+	uint_t		sps_proto;
+	char		*sps_propval;
+	nvlist_t	*sps_proplist;
+	boolean_t	sps_parsable;
+	boolean_t	sps_addrprop;
+	boolean_t	sps_ifprop;
+	boolean_t	sps_modprop;
+	ipadm_status_t	sps_status;
+	ipadm_status_t	sps_retstatus;
+	ofmt_handle_t	sps_ofmt;
+} show_prop_state_t;
+
+typedef struct show_addr_state {
+	boolean_t	sa_parsable;
+	boolean_t	sa_persist;
+	ofmt_handle_t	sa_ofmt;
+} show_addr_state_t;
+
+typedef struct show_if_state {
+	boolean_t	si_parsable;
+	ofmt_handle_t	si_ofmt;
+} show_if_state_t;
+
+typedef struct show_addr_args_s {
+	show_addr_state_t	*sa_state;
+	ipadm_addr_info_t	*sa_info;
+} show_addr_args_t;
+
+typedef struct show_if_args_s {
+	show_if_state_t *si_state;
+	ipadm_if_info_t *si_info;
+} show_if_args_t;
+
+typedef enum {
+	SA_ADDROBJ,
+	SA_TYPE,
+	SA_STATE,
+	SA_CURRENT,
+	SA_PERSISTENT,
+	SA_ADDR
+} sa_field_index_t;
+
+typedef enum {
+	SI_IFNAME,
+	SI_STATE,
+	SI_CURRENT,
+	SI_PERSISTENT
+} si_field_index_t;
+
+static ofmt_field_t show_addr_fields[] = {
+/* name,	field width,	id,		callback */
+{ "ADDROBJ",	18,		SA_ADDROBJ,	print_sa_cb},
+{ "TYPE",	9,		SA_TYPE,	print_sa_cb},
+{ "STATE",	13,		SA_STATE,	print_sa_cb},
+{ "CURRENT",	8,		SA_CURRENT,	print_sa_cb},
+{ "PERSISTENT",	11,		SA_PERSISTENT,	print_sa_cb},
+{ "ADDR",	46,		SA_ADDR,	print_sa_cb},
+{ NULL,		0,		0,		NULL}
+};
+
+static ofmt_field_t show_if_fields[] = {
+/* name,	field width,	id,		callback */
+{ "IFNAME",	11,		SI_IFNAME,	print_si_cb},
+{ "STATE",	9,		SI_STATE,	print_si_cb},
+{ "CURRENT",	12,		SI_CURRENT,	print_si_cb},
+{ "PERSISTENT",	11,		SI_PERSISTENT,	print_si_cb},
+{ NULL,		0,		0,		NULL}
+};
+
+#define	IPADM_ALL_BITS	((uint_t)-1)
+typedef struct intf_mask {
+	char		*name;
+	uint64_t	bits;
+	uint64_t	mask;
+} fmask_t;
+
+/*
+ * Handle to libipadm. Opened in main() before the sub-command specific
+ * function is called and is closed before the program exits.
+ */
+ipadm_handle_t	iph = NULL;
+
+/*
+ * Opaque ipadm address object. Used by all the address management subcommands.
+ */
+ipadm_addrobj_t	ipaddr = NULL;
+
+static char *progname;
+
+static void	die(const char *, ...);
+static void	die_opterr(int, int, const char *);
+static void	warn_ipadmerr(ipadm_status_t, const char *, ...);
+static void 	ipadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
+static void 	ipadm_check_propstr(const char *, boolean_t, const char *);
+static void 	process_misc_addrargs(int, char **, const char *, int *,
+		    uint32_t *);
+
+static void
+usage(void)
+{
+	int	i;
+	cmd_t	*cmdp;
+
+	(void) fprintf(stderr,
+	    gettext("usage:  ipadm <subcommand> <args> ...\n"));
+	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
+		cmdp = &cmds[i];
+		if (strcmp(cmdp->c_name, "init-prop") == 0)
+			continue;
+		if (cmdp->c_usage != NULL)
+			(void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
+	}
+
+	ipadm_destroy_addrobj(ipaddr);
+	ipadm_close(iph);
+	exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int	i;
+	cmd_t	*cmdp;
+	ipadm_status_t status;
+
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+
+	if ((progname = strrchr(argv[0], '/')) == NULL)
+		progname = argv[0];
+	else
+		progname++;
+
+	if (argc < 2)
+		usage();
+
+	status = ipadm_open(&iph, 0);
+	if (status != IPADM_SUCCESS) {
+		die("Could not open handle to library - %s",
+		    ipadm_status2str(status));
+	}
+
+	for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
+		cmdp = &cmds[i];
+		if (strcmp(argv[1], cmdp->c_name) == 0) {
+			cmdp->c_fn(argc - 1, &argv[1], gettext(cmdp->c_usage));
+			ipadm_destroy_addrobj(ipaddr);
+			ipadm_close(iph);
+			exit(0);
+		}
+	}
+
+	(void) fprintf(stderr, gettext("%s: unknown subcommand '%s'\n"),
+	    progname, argv[1]);
+	usage();
+
+	return (0);
+}
+
+/*
+ * Create an IP interface for which no saved configuration exists in the
+ * persistent store.
+ */
+static void
+do_create_if(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		option;
+	uint32_t	flags = IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":t", if_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 't':
+			/*
+			 * "ifconfig" mode - plumb interface, but do not
+			 * restore settings that may exist in db.
+			 */
+			flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+	if (optind != (argc - 1))
+		die("Usage: %s", use);
+	status = ipadm_create_if(iph, argv[optind], AF_UNSPEC, flags);
+	if (status != IPADM_SUCCESS) {
+		die("Could not create %s : %s",
+		    argv[optind], ipadm_status2str(status));
+	}
+}
+
+/*
+ * Enable an IP interface based on the persistent configuration for
+ * that interface.
+ */
+static void
+do_enable_if(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	if (flags & IPADM_OPT_PERSIST)
+		die("persistent operation not supported for enable-if");
+	status = ipadm_enable_if(iph, argv[index], flags);
+	if (status == IPADM_ALL_ADDRS_NOT_ENABLED) {
+		warn_ipadmerr(status, "");
+	} else if (status != IPADM_SUCCESS) {
+		die("Could not enable %s : %s",
+		    argv[optind], ipadm_status2str(status));
+	}
+}
+
+/*
+ * Remove an IP interface from both active and persistent configuration.
+ */
+static void
+do_delete_if(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	uint32_t	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	if (argc != 2)
+		die("Usage: %s", use);
+
+	status = ipadm_delete_if(iph, argv[1], AF_UNSPEC, flags);
+	if (status != IPADM_SUCCESS) {
+		die("Could not delete %s: %s",
+		    argv[optind], ipadm_status2str(status));
+	}
+}
+
+/*
+ * Disable an IP interface by removing it from active configuration.
+ */
+static void
+do_disable_if(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	if (flags & IPADM_OPT_PERSIST)
+		die("persistent operation not supported for disable-if");
+	status = ipadm_disable_if(iph, argv[index], flags);
+	if (status != IPADM_SUCCESS) {
+		die("Could not disable %s: %s",
+		    argv[optind], ipadm_status2str(status));
+	}
+}
+
+/*
+ * called in from print_prop_cb() and does the job of printing each
+ * individual column in the 'ipadm show-*prop' output.
+ */
+static void
+print_prop(show_prop_state_t *statep, uint_t flags, char *buf, size_t bufsize)
+{
+	const char		*prop_name = statep->sps_pname;
+	char			*ifname = statep->sps_ifname;
+	char			*propval = statep->sps_propval;
+	uint_t			proto = statep->sps_proto;
+	size_t			propsize = MAXPROPVALLEN;
+	char			*object;
+	ipadm_status_t		status;
+
+	if (statep->sps_ifprop) {
+		status = ipadm_get_ifprop(iph, ifname, prop_name, propval,
+		    &propsize, proto, flags);
+		object = ifname;
+	} else if (statep->sps_modprop) {
+		status = ipadm_get_prop(iph, prop_name, propval, &propsize,
+		    proto, flags);
+		object = ipadm_proto2str(proto);
+	} else {
+		status = ipadm_get_addrprop(iph, prop_name, propval, &propsize,
+		    statep->sps_aobjname, flags);
+		object = statep->sps_aobjname;
+	}
+
+	if (status != IPADM_SUCCESS) {
+		if (status == IPADM_PROP_UNKNOWN ||
+		    status == IPADM_INVALID_ARG) {
+			warn_ipadmerr(status, "cannot get property '%s' for "
+			    "'%s'", prop_name, object);
+		} else if (status == IPADM_NOTSUP) {
+			warn_ipadmerr(status, "'%s'", object);
+		} else if (status == IPADM_NOTFOUND) {
+			if (flags & IPADM_OPT_PERSIST) {
+				propval[0] = '\0';
+				goto cont;
+			} else {
+				warn_ipadmerr(status, "no such object '%s'",
+				    object);
+			}
+		} else if (status == IPADM_ENXIO) {
+			/* the interface is probably disabled */
+			propval[0] = '\0';
+			goto cont;
+		}
+		statep->sps_status = status;
+		statep->sps_retstatus = status;
+		return;
+	}
+cont:
+	statep->sps_status = IPADM_SUCCESS;
+	(void) snprintf(buf, bufsize, "%s", propval);
+}
+
+/*
+ * callback function which displays output for set-prop, set-ifprop and
+ * set-addrprop subcommands.
+ */
+static boolean_t
+print_prop_cb(ofmt_arg_t *ofarg, char *buf, size_t bufsize)
+{
+	show_prop_state_t	*statep = ofarg->ofmt_cbarg;
+	const char		*propname = statep->sps_pname;
+	uint_t			proto = statep->sps_proto;
+	boolean_t		cont = _B_TRUE;
+
+	/*
+	 * Fail retrieving remaining fields, if you fail
+	 * to retrieve a field.
+	 */
+	if (statep->sps_status != IPADM_SUCCESS)
+		return (_B_FALSE);
+
+	switch (ofarg->ofmt_id) {
+	case IPADM_PROPFIELD_IFNAME:
+		(void) snprintf(buf, bufsize, "%s", statep->sps_ifname);
+		break;
+	case IPADM_PROPFIELD_PROTO:
+		(void) snprintf(buf, bufsize, "%s", ipadm_proto2str(proto));
+		break;
+	case IPADM_PROPFIELD_ADDROBJ:
+		(void) snprintf(buf, bufsize, "%s", statep->sps_aobjname);
+		break;
+	case IPADM_PROPFIELD_PROPERTY:
+		(void) snprintf(buf, bufsize, "%s", propname);
+		break;
+	case IPADM_PROPFIELD_PERM:
+		print_prop(statep, IPADM_OPT_PERM, buf, bufsize);
+		break;
+	case IPADM_PROPFIELD_CURRENT:
+		print_prop(statep, IPADM_OPT_ACTIVE, buf, bufsize);
+		break;
+	case IPADM_PROPFIELD_PERSISTENT:
+		print_prop(statep, IPADM_OPT_PERSIST, buf, bufsize);
+		break;
+	case IPADM_PROPFIELD_DEFAULT:
+		print_prop(statep, IPADM_OPT_DEFAULT, buf, bufsize);
+		break;
+	case IPADM_PROPFIELD_POSSIBLE:
+		print_prop(statep, IPADM_OPT_POSSIBLE, buf, bufsize);
+		break;
+	}
+	if (statep->sps_status != IPADM_SUCCESS)
+		cont = _B_FALSE;
+	return (cont);
+}
+
+/*
+ * Callback function called by the property walker (ipadm_walk_prop() or
+ * ipadm_walk_proptbl()), for every matched property. This function in turn
+ * calls ofmt_print() to print property information.
+ */
+boolean_t
+show_property(void *arg, const char *pname, uint_t proto)
+{
+	show_prop_state_t	*statep = arg;
+
+	statep->sps_pname = pname;
+	statep->sps_proto = proto;
+	statep->sps_status = IPADM_SUCCESS;
+	ofmt_print(statep->sps_ofmt, arg);
+
+	/*
+	 * if an object is not found or operation is not supported then
+	 * stop the walker.
+	 */
+	if (statep->sps_status == IPADM_NOTFOUND ||
+	    statep->sps_status == IPADM_NOTSUP)
+		return (_B_FALSE);
+	return (_B_TRUE);
+}
+
+/*
+ * 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
+ * information
+ */
+static void
+show_properties(void *arg, int prop_class)
+{
+	show_prop_state_t	*statep = arg;
+	nvlist_t 		*nvl = statep->sps_proplist;
+	uint_t			proto = statep->sps_proto;
+	nvpair_t		*curr_nvp;
+	char 			*buf, *name;
+	ipadm_status_t		status;
+
+	/* allocate sufficient buffer to hold a property value */
+	if ((buf = malloc(MAXPROPVALLEN)) == NULL)
+		die("insufficient memory");
+	statep->sps_propval = buf;
+
+	/* if no properties were specified, display all the properties */
+	if (nvl == NULL) {
+		(void) ipadm_walk_proptbl(proto, prop_class, show_property,
+		    statep);
+	} else {
+		for (curr_nvp = nvlist_next_nvpair(nvl, NULL); curr_nvp;
+		    curr_nvp = nvlist_next_nvpair(nvl, curr_nvp)) {
+			name = nvpair_name(curr_nvp);
+			status = ipadm_walk_prop(name, proto, prop_class,
+			    show_property, statep);
+			if (status == IPADM_PROP_UNKNOWN)
+				(void) show_property(statep, name, proto);
+		}
+	}
+
+	free(buf);
+}
+
+/*
+ * Display information for all or specific interface properties, either for a
+ * given interface or for all the interfaces in the system.
+ */
+static void
+do_show_ifprop(int argc, char **argv, const char *use)
+{
+	int 		option;
+	nvlist_t 	*proplist = NULL;
+	char		*fields_str = NULL;
+	char 		*ifname;
+	ofmt_handle_t	ofmt;
+	ofmt_status_t	oferr;
+	uint_t		ofmtflags = 0;
+	uint_t		proto;
+	boolean_t	m_arg = _B_FALSE;
+	char		*protostr;
+	ipadm_if_info_t	*ifinfo, *ifp;
+	ipadm_status_t	status;
+	show_prop_state_t state;
+
+	opterr = 0;
+	bzero(&state, sizeof (state));
+	state.sps_propval = NULL;
+	state.sps_parsable = _B_FALSE;
+	state.sps_ifprop = _B_TRUE;
+	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
+	while ((option = getopt_long(argc, argv, ":p:m:co:",
+	    show_ifprop_longopts, NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (ipadm_str2nvlist(optarg, &proplist,
+			    IPADM_NORVAL) != 0)
+				die("invalid interface properties specified");
+			break;
+		case 'c':
+			state.sps_parsable = _B_TRUE;
+			break;
+		case 'o':
+			fields_str = optarg;
+			break;
+		case 'm':
+			if (m_arg)
+				die("cannot specify more than one -m");
+			m_arg = _B_TRUE;
+			protostr = optarg;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+
+	if (optind == argc - 1)
+		ifname = argv[optind];
+	else if (optind != argc)
+		die("Usage: %s", use);
+	else
+		ifname = NULL;
+
+	if (!m_arg)
+		protostr = "ip";
+	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
+		die("invalid protocol '%s' specified", protostr);
+
+	state.sps_proto = proto;
+	state.sps_proplist = proplist;
+
+	if (state.sps_parsable)
+		ofmtflags |= OFMT_PARSABLE;
+	oferr = ofmt_open(fields_str, intfprop_fields, ofmtflags, 0, &ofmt);
+	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
+	state.sps_ofmt = ofmt;
+
+	/* retrieve interface(s) and print the properties */
+	status = ipadm_if_info(iph, ifname, &ifinfo, 0, LIFC_DEFAULT);
+	if (ifname != NULL && status == IPADM_ENXIO)
+		die("no such object '%s': %s", ifname,
+		    ipadm_status2str(status));
+	if (status != IPADM_SUCCESS)
+		die("Error retrieving interface(s): %s",
+		    ipadm_status2str(status));
+	for (ifp = ifinfo; ifp; ifp = ifp->ifi_next) {
+		(void) strlcpy(state.sps_ifname, ifp->ifi_name, LIFNAMSIZ);
+		state.sps_proto = proto;
+		show_properties(&state, IPADMPROP_CLASS_IF);
+	}
+	if (ifinfo)
+		ipadm_free_if_info(ifinfo);
+
+	nvlist_free(proplist);
+	ofmt_close(ofmt);
+
+	if (state.sps_retstatus != IPADM_SUCCESS) {
+		ipadm_close(iph);
+		exit(EXIT_FAILURE);
+	}
+}
+
+/*
+ * set/reset the interface property for a given interface.
+ */
+static void
+set_ifprop(int argc, char **argv, boolean_t reset, const char *use)
+{
+	int 			option;
+	ipadm_status_t 		status = IPADM_SUCCESS;
+	boolean_t 		p_arg = _B_FALSE;
+	boolean_t		m_arg = _B_FALSE;
+	char 			*ifname, *nv, *protostr;
+	char			*prop_name, *prop_val;
+	uint_t			flags = IPADM_OPT_PERSIST;
+	uint_t			proto;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":m:p:t",
+	    set_ifprop_longopts, NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (p_arg)
+				die("-p must be specified once only");
+			p_arg = _B_TRUE;
+
+			ipadm_check_propstr(optarg, reset, use);
+			nv = optarg;
+			break;
+		case 'm':
+			if (m_arg)
+				die("-m must be specified once only");
+			m_arg = _B_TRUE;
+			protostr = optarg;
+			break;
+		case 't':
+			flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+
+	if (!m_arg || !p_arg || optind != argc - 1)
+		die("Usage: %s", use);
+
+	ifname = argv[optind];
+
+	prop_name = nv;
+	prop_val = strchr(nv, '=');
+	if (prop_val != NULL)
+		*prop_val++ = '\0';
+
+	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
+		die("invalid protocol '%s' specified", protostr);
+
+	if (reset)
+		flags |= IPADM_OPT_DEFAULT;
+	else
+		flags |= IPADM_OPT_ACTIVE;
+	status = ipadm_set_ifprop(iph, ifname, prop_name, prop_val, proto,
+	    flags);
+
+done:
+	if (status != IPADM_SUCCESS) {
+		if (reset)
+			die("reset-ifprop: %s: %s",
+			    prop_name, ipadm_status2str(status));
+		else
+			die("set-ifprop: %s: %s",
+			    prop_name, ipadm_status2str(status));
+	}
+}
+
+static void
+do_set_ifprop(int argc, char **argv, const char *use)
+{
+	set_ifprop(argc, argv, _B_FALSE, use);
+}
+
+static void
+do_reset_ifprop(int argc, char **argv, const char *use)
+{
+	set_ifprop(argc, argv, _B_TRUE, use);
+}
+
+/*
+ * Display information for all or specific protocol properties, either for a
+ * given protocol or for supported protocols (IP/IPv4/IPv6/TCP/UDP/SCTP)
+ */
+static void
+do_show_prop(int argc, char **argv, const char *use)
+{
+	char 			option;
+	nvlist_t 		*proplist = NULL;
+	char			*fields_str = NULL;
+	char 			*protostr;
+	show_prop_state_t 	state;
+	ofmt_handle_t		ofmt;
+	ofmt_status_t		oferr;
+	uint_t			ofmtflags = 0;
+	uint_t			proto;
+	boolean_t		p_arg = _B_FALSE;
+
+	opterr = 0;
+	bzero(&state, sizeof (state));
+	state.sps_propval = NULL;
+	state.sps_parsable = _B_FALSE;
+	state.sps_modprop = _B_TRUE;
+	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
+	while ((option = getopt_long(argc, argv, ":p:co:", show_prop_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (p_arg)
+				die("-p must be specified once only");
+			p_arg = _B_TRUE;
+			if (ipadm_str2nvlist(optarg, &proplist,
+			    IPADM_NORVAL) != 0)
+				die("invalid protocol properties specified");
+			break;
+		case 'c':
+			state.sps_parsable = _B_TRUE;
+			break;
+		case 'o':
+			fields_str = optarg;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+	if (optind == argc - 1) {
+		protostr =  argv[optind];
+		if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
+			die("invalid protocol '%s' specified", protostr);
+		state.sps_proto = proto;
+	} else if (optind != argc) {
+		die("Usage: %s", use);
+	} else {
+		if (p_arg)
+			die("protocol must be specified when "
+			    "property name is used");
+		state.sps_proto = MOD_PROTO_NONE;
+	}
+
+	state.sps_proplist = proplist;
+
+	if (state.sps_parsable)
+		ofmtflags |= OFMT_PARSABLE;
+	else
+		ofmtflags |= OFMT_WRAP;
+	oferr = ofmt_open(fields_str, modprop_fields, ofmtflags, 0, &ofmt);
+	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
+	state.sps_ofmt = ofmt;
+
+	/* handles all the errors */
+	show_properties(&state, IPADMPROP_CLASS_MODULE);
+
+	nvlist_free(proplist);
+	ofmt_close(ofmt);
+
+	if (state.sps_retstatus != IPADM_SUCCESS) {
+		ipadm_close(iph);
+		exit(EXIT_FAILURE);
+	}
+}
+
+/*
+ * Checks to see if there are any modifiers, + or -. If there are modifiers
+ * then sets IPADM_OPT_APPEND or IPADM_OPT_REMOVE, accordingly.
+ */
+static void
+parse_modifiers(char *pstr, uint_t *flags, const char *use)
+{
+	char *p;
+
+	p = strpbrk(pstr, "+-");
+	if (p == NULL)
+		return;		/* Nothing to parse, return */
+
+	if (p[1] != '=')
+		die("badly used modifier.\n%s", use);
+
+	if (p[0] == '+')
+		*flags |= IPADM_OPT_APPEND;
+	else
+		*flags |= IPADM_OPT_REMOVE;
+}
+
+/*
+ * set/reset the protocol property for a given protocol.
+ */
+static void
+set_prop(int argc, char **argv, boolean_t reset, const char *use)
+{
+	int 			option;
+	ipadm_status_t 		status = IPADM_SUCCESS;
+	char 			*protostr, *nv, *prop_name, *prop_val;
+	boolean_t 		p_arg = _B_FALSE;
+	uint_t 			proto;
+	uint_t			flags = IPADM_OPT_PERSIST;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":p:t", set_prop_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (p_arg)
+				die("-p must be specified once only");
+			p_arg = _B_TRUE;
+
+			ipadm_check_propstr(optarg, reset, use);
+			nv = optarg;
+			break;
+		case 't':
+			flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+
+	if (!p_arg || optind != argc - 1)
+		die("Usage: %s", use);
+
+	parse_modifiers(nv, &flags, use);
+	prop_name = nv;
+	prop_val = strchr(nv, '=');
+	if (prop_val != NULL) {
+		if (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))
+			*(prop_val - 1) = '\0';
+		*prop_val++ = '\0';
+	}
+	protostr = argv[optind];
+	if ((proto = ipadm_str2proto(protostr)) == MOD_PROTO_NONE)
+		die("invalid protocol '%s' specified", protostr);
+
+	if (reset)
+		flags |= IPADM_OPT_DEFAULT;
+	else
+		flags |= IPADM_OPT_ACTIVE;
+	status = ipadm_set_prop(iph, prop_name, prop_val, proto, flags);
+done:
+	if (status != IPADM_SUCCESS) {
+		if (reset)
+			die("reset-prop: %s: %s",
+			    prop_name, ipadm_status2str(status));
+		else
+			die("set-prop: %s: %s",
+			    prop_name, ipadm_status2str(status));
+	}
+}
+
+static void
+do_set_prop(int argc, char **argv, const char *use)
+{
+	set_prop(argc, argv, _B_FALSE, use);
+}
+
+static void
+do_reset_prop(int argc, char **argv, const char *use)
+{
+	set_prop(argc, argv,  _B_TRUE, use);
+}
+
+/*
+ * Called on reboot by /lib/inet/netstart. Reads the persistent store
+ * and applies all the global protocol properties.
+ */
+/* ARGSUSED */
+static void
+do_init_prop(int argc, char **argv, const char *use)
+{
+	(void) ipadm_init_prop();
+}
+
+/* PRINTFLIKE1 */
+static void
+warn(const char *format, ...)
+{
+	va_list alist;
+
+	format = gettext(format);
+	(void) fprintf(stderr, gettext("%s: warning: "), progname);
+
+	va_start(alist, format);
+	(void) vfprintf(stderr, format, alist);
+	va_end(alist);
+
+	(void) fprintf(stderr, "\n");
+}
+
+/* PRINTFLIKE1 */
+static void
+die(const char *format, ...)
+{
+	va_list alist;
+
+	format = gettext(format);
+	(void) fprintf(stderr, "%s: ", progname);
+
+	va_start(alist, format);
+	(void) vfprintf(stderr, format, alist);
+	va_end(alist);
+
+	(void) putchar('\n');
+
+	ipadm_destroy_addrobj(ipaddr);
+	ipadm_close(iph);
+	exit(EXIT_FAILURE);
+}
+
+static void
+die_opterr(int opt, int opterr, const char *usage)
+{
+	switch (opterr) {
+	case ':':
+		die("option '-%c' requires a value\nusage: %s", opt,
+		    gettext(usage));
+		break;
+	case '?':
+	default:
+		die("unrecognized option '-%c'\nusage: %s", opt,
+		    gettext(usage));
+		break;
+	}
+}
+
+/* PRINTFLIKE2 */
+static void
+warn_ipadmerr(ipadm_status_t err, const char *format, ...)
+{
+	va_list alist;
+
+	format = gettext(format);
+	(void) fprintf(stderr, gettext("%s: warning: "), progname);
+
+	va_start(alist, format);
+	(void) vfprintf(stderr, format, alist);
+	va_end(alist);
+
+	(void) fprintf(stderr, "%s\n", ipadm_status2str(err));
+}
+
+static void
+process_static_addrargs(const char *use, char *addrarg, const char *aobjname)
+{
+	int		option;
+	char		*val;
+	char		*laddr = NULL;
+	char		*raddr = NULL;
+	char		*save_input_arg = addrarg;
+	boolean_t	found_mismatch = _B_FALSE;
+	ipadm_status_t	status;
+	enum		{ A_LOCAL, A_REMOTE };
+	static char	*addr_optstr[] = {
+		"local",
+		"remote",
+		NULL,
+	};
+
+	while (*addrarg != '\0') {
+		option = getsubopt(&addrarg, addr_optstr, &val);
+		switch (option) {
+		case A_LOCAL:
+			if (laddr != NULL)
+				die("Multiple local addresses provided");
+			laddr = val;
+			break;
+		case A_REMOTE:
+			if (raddr != NULL)
+				die("Multiple remote addresses provided");
+			raddr = val;
+			break;
+		default:
+			if (found_mismatch)
+				die("Invalid address provided\nusage: %s", use);
+			found_mismatch = _B_TRUE;
+			break;
+		}
+	}
+	if (raddr != NULL && laddr == NULL)
+		die("Missing local address\nusage: %s", use);
+
+	/* If only one address is provided, it is assumed a local address. */
+	if (laddr == NULL) {
+		if (found_mismatch)
+			laddr = save_input_arg;
+		else
+			die("Missing local address\nusage: %s", use);
+	}
+
+	/* Initialize the addrobj for static addresses. */
+	status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname, &ipaddr);
+	if (status != IPADM_SUCCESS) {
+		die("Error in creating address object: %s",
+		    ipadm_status2str(status));
+	}
+
+	/* Set the local and remote addresses */
+	status = ipadm_set_addr(ipaddr, laddr, AF_UNSPEC);
+	if (status != IPADM_SUCCESS) {
+		die("Error in setting local address: %s",
+		    ipadm_status2str(status));
+	}
+	if (raddr != NULL) {
+		status = ipadm_set_dst_addr(ipaddr, raddr, AF_UNSPEC);
+		if (status != IPADM_SUCCESS) {
+			die("Error in setting remote address: %s",
+			    ipadm_status2str(status));
+		}
+	}
+}
+
+static void
+process_addrconf_addrargs(const char *use, char *addrarg)
+{
+	int		option;
+	char		*val;
+	enum		{ P_STATELESS, P_STATEFUL };
+	static char	*addr_optstr[] = {
+		"stateless",
+		"stateful",
+		NULL,
+	};
+	boolean_t	stateless;
+	boolean_t	stateless_arg = _B_FALSE;
+	boolean_t	stateful;
+	boolean_t	stateful_arg = _B_FALSE;
+	ipadm_status_t	status;
+
+	while (*addrarg != '\0') {
+		option = getsubopt(&addrarg, addr_optstr, &val);
+		switch (option) {
+		case P_STATELESS:
+			if (stateless_arg)
+				die("Duplicate option");
+			if (strcmp(val, "yes") == 0)
+				stateless = _B_TRUE;
+			else if (strcmp(val, "no") == 0)
+				stateless = _B_FALSE;
+			else
+				die("Invalid argument");
+			stateless_arg = _B_TRUE;
+			break;
+		case P_STATEFUL:
+			if (stateful_arg)
+				die("Duplicate option");
+			if (strcmp(val, "yes") == 0)
+				stateful = _B_TRUE;
+			else if (strcmp(val, "no") == 0)
+				stateful = _B_FALSE;
+			else
+				die("Invalid argument");
+			stateful_arg = _B_TRUE;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+
+	if (!stateless_arg && !stateful_arg)
+		die("Invalid arguments for option -p");
+
+	/* Set the addrobj fields for addrconf */
+	if (stateless_arg) {
+		status = ipadm_set_stateless(ipaddr, stateless);
+		if (status != IPADM_SUCCESS) {
+			die("Error in setting stateless option: %s",
+			    ipadm_status2str(status));
+		}
+	}
+	if (stateful_arg) {
+		status = ipadm_set_stateful(ipaddr, stateful);
+		if (status != IPADM_SUCCESS) {
+			die("Error in setting stateful option: %s",
+			    ipadm_status2str(status));
+		}
+	}
+}
+
+/*
+ * Creates static, dhcp or addrconf addresses and associates the created
+ * addresses with the specified address object name.
+ */
+static void
+do_create_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		option;
+	uint32_t	flags =
+	    IPADM_OPT_PERSIST|IPADM_OPT_ACTIVE|IPADM_OPT_UP;
+	char		*cp;
+	char		*atype = NULL;
+	char		*static_arg = NULL;
+	char		*addrconf_arg = NULL;
+	char		*interface_id = NULL;
+	char		*wait = 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 */
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":T:a:di:p:w:t",
+	    addr_longopts, NULL)) != -1) {
+		switch (option) {
+		case 'T':
+			atype = optarg;
+			break;
+		case 'a':
+			static_arg = optarg;
+			s_opt = _B_TRUE;
+			break;
+		case 'd':
+			flags &= ~IPADM_OPT_UP;
+			s_opt = _B_TRUE;
+			break;
+		case 'i':
+			interface_id = optarg;
+			auto_opt = _B_TRUE;
+			break;
+		case 'p':
+			addrconf_arg = optarg;
+			auto_opt = _B_TRUE;
+			break;
+		case 'w':
+			wait = optarg;
+			dhcp_opt = _B_TRUE;
+			break;
+		case 't':
+			flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+	if (atype == NULL || optind != (argc - 1)) {
+		die("Invalid arguments\nusage: %s", use);
+	} else if ((cp = strchr(argv[optind], '/')) == NULL ||
+	    strlen(++cp) == 0) {
+		die("invalid address object name: %s\nusage: %s",
+		    argv[optind], use);
+	}
+
+	/*
+	 * Allocate and initialize the addrobj based on the address type.
+	 */
+	if (strcmp(atype, "static") == 0) {
+		if (static_arg == NULL || auto_opt || dhcp_opt) {
+			die("Invalid arguments for type %s\nusage: %s",
+			    atype, use);
+		}
+		process_static_addrargs(use, static_arg, argv[optind]);
+	} else if (strcmp(atype, "dhcp") == 0) {
+		if (auto_opt || s_opt) {
+			die("Invalid arguments for type %s\nusage: %s",
+			    atype, use);
+		}
+
+		/* Initialize the addrobj for dhcp addresses. */
+		status = ipadm_create_addrobj(IPADM_ADDR_DHCP, argv[optind],
+		    &ipaddr);
+		if (status != IPADM_SUCCESS) {
+			die("Error in creating address object: %s",
+			    ipadm_status2str(status));
+		}
+		if (wait != NULL) {
+			int32_t ipadm_wait;
+
+			if (strcmp(wait, "forever") == 0) {
+				ipadm_wait = IPADM_DHCP_WAIT_FOREVER;
+			} else {
+				char *end;
+				long timeout = strtol(wait, &end, 10);
+
+				if (*end != '\0' || timeout < 0)
+					die("Invalid argument");
+				ipadm_wait = (int32_t)timeout;
+			}
+			status = ipadm_set_wait_time(ipaddr, ipadm_wait);
+			if (status != IPADM_SUCCESS) {
+				die("Error in setting wait time: %s",
+				    ipadm_status2str(status));
+			}
+		}
+	} else if (strcmp(atype, "addrconf") == 0) {
+		if (dhcp_opt || s_opt) {
+			die("Invalid arguments for type %s\nusage: %s",
+			    atype, use);
+		}
+
+		/* Initialize the addrobj for dhcp addresses. */
+		status = ipadm_create_addrobj(IPADM_ADDR_IPV6_ADDRCONF,
+		    argv[optind], &ipaddr);
+		if (status != IPADM_SUCCESS) {
+			die("Error in creating address object: %s",
+			    ipadm_status2str(status));
+		}
+		if (interface_id != NULL) {
+			status = ipadm_set_interface_id(ipaddr, interface_id);
+			if (status != IPADM_SUCCESS) {
+				die("Error in setting interface ID: %s",
+				    ipadm_status2str(status));
+			}
+		}
+		if (addrconf_arg)
+			process_addrconf_addrargs(use, addrconf_arg);
+	} else {
+		die("Invalid address type %s", atype);
+	}
+
+	status = ipadm_create_addr(iph, ipaddr, flags);
+	if (status == IPADM_DHCP_IPC_TIMEOUT)
+		warn_ipadmerr(status, "");
+	else if (status != IPADM_SUCCESS)
+		die("Could not create address: %s", ipadm_status2str(status));
+}
+
+/*
+ * Used by some address management functions to parse the command line
+ * arguments and create `ipaddr' address object.
+ */
+static void
+process_misc_addrargs(int argc, char *argv[], const char *use, int *index,
+    uint32_t *flags)
+{
+	int		option;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":t", addr_misc_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 't':
+			*flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+	if (optind != (argc - 1))
+		die("Usage: %s", use);
+
+	*index = optind;
+}
+
+/*
+ * Remove an addrobj from both active and persistent configuration.
+ */
+static void
+do_delete_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+	int		option;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":r", addr_misc_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'r':
+			flags |= IPADM_OPT_RELEASE;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+	if (optind != (argc - 1))
+		die("Usage: %s", use);
+
+	status = ipadm_delete_addr(iph, argv[optind], flags);
+	if (status != IPADM_SUCCESS) {
+		die("could not delete address: %s",
+		    ipadm_status2str(status));
+	}
+}
+
+/*
+ * Enable an IP address based on the persistent configuration for that
+ * IP address
+ */
+static void
+do_enable_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	if (flags & IPADM_OPT_PERSIST)
+		die("persistent operation not supported for enable-addr");
+
+	status = ipadm_enable_addr(iph, argv[index], flags);
+	if (status != IPADM_SUCCESS)
+		die("could not enable address: %s", ipadm_status2str(status));
+}
+
+/*
+ * Mark the address identified by addrobj 'up'
+ */
+static void
+do_up_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	status = ipadm_up_addr(iph, argv[index], flags);
+	if (status != IPADM_SUCCESS) {
+		die("Could not mark the address up: %s",
+		    ipadm_status2str(status));
+	}
+}
+
+/*
+ * Disable the specified addrobj by removing it from active cofiguration
+ */
+static void
+do_disable_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	if (flags & IPADM_OPT_PERSIST)
+		die("persistent operation not supported for disable-addr");
+
+	status = ipadm_disable_addr(iph, argv[index], flags);
+	if (status != IPADM_SUCCESS) {
+		die("could not disable address: %s",
+		    ipadm_status2str(status));
+	}
+}
+
+/*
+ * Mark the address identified by addrobj 'down'
+ */
+static void
+do_down_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		index;
+	uint32_t 	flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	process_misc_addrargs(argc, argv, use, &index, &flags);
+	status = ipadm_down_addr(iph, argv[index], flags);
+	if (status != IPADM_SUCCESS)
+		die("Could not mark the address down: %s",
+		    ipadm_status2str(status));
+}
+
+/*
+ * Restart DAD for static address. Extend lease duration for DHCP addresses
+ */
+static void
+do_refresh_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t	status;
+	int		option;
+	uint32_t	flags = 0;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":i", addr_misc_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'i':
+			flags |= IPADM_OPT_INFORM;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+	if (optind != (argc - 1))
+		die("Usage: %s", use);
+
+	status = ipadm_refresh_addr(iph, argv[optind], flags);
+	if (status == IPADM_DHCP_IPC_TIMEOUT)
+		warn_ipadmerr(status, "");
+	else if (status != IPADM_SUCCESS)
+		die("could not refresh address %s", ipadm_status2str(status));
+}
+
+static void
+sockaddr2str(const struct sockaddr_storage *ssp, char *buf, uint_t bufsize)
+{
+	socklen_t socklen;
+	struct sockaddr *sp = (struct sockaddr *)ssp;
+
+	switch (ssp->ss_family) {
+	case AF_INET:
+		socklen = sizeof (struct sockaddr_in);
+		break;
+	case AF_INET6:
+		socklen = sizeof (struct sockaddr_in6);
+		break;
+	default:
+		(void) strlcpy(buf, STR_UNKNOWN_VAL, bufsize);
+		return;
+	}
+
+	(void) getnameinfo(sp, socklen, buf, bufsize, NULL, 0,
+	    (NI_NOFQDN | NI_NUMERICHOST));
+}
+
+static void
+flags2str(uint64_t flags, fmask_t *tbl, boolean_t is_bits,
+    char *buf, uint_t bufsize)
+{
+	int		i;
+	boolean_t	first = _B_TRUE;
+
+	if (is_bits) {
+		for (i = 0;  tbl[i].name; i++) {
+			if ((flags & tbl[i].mask) == tbl[i].bits)
+				(void) strlcat(buf, tbl[i].name, bufsize);
+			else
+				(void) strlcat(buf, "-", bufsize);
+		}
+	} else {
+		for (i = 0; tbl[i].name; i++) {
+			if ((flags & tbl[i].mask) == tbl[i].bits) {
+				if (!first)
+					(void) strlcat(buf, ",", bufsize);
+				(void) strlcat(buf, tbl[i].name, bufsize);
+				first = _B_FALSE;
+			}
+		}
+	}
+}
+
+static boolean_t
+print_sa_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+	show_addr_args_t	*arg = ofarg->ofmt_cbarg;
+	ipadm_addr_info_t	*ainfo = arg->sa_info;
+	char			interface[LIFNAMSIZ];
+	char			addrbuf[MAXPROPVALLEN];
+	char			dstbuf[MAXPROPVALLEN];
+	char			prefixlenstr[MAXPROPVALLEN];
+	int			prefixlen;
+	struct sockaddr_in	*sin;
+	struct sockaddr_in6	*sin6;
+	sa_family_t		af;
+	char			*phyname = NULL;
+	struct ifaddrs		*ifa = &ainfo->ia_ifa;
+	fmask_t cflags_mask[] = {
+		{ "U",	IA_UP,			IA_UP		},
+		{ "u",	IA_UNNUMBERED,		IA_UNNUMBERED	},
+		{ "p",	IA_PRIVATE,		IA_PRIVATE	},
+		{ "t",	IA_TEMPORARY,		IA_TEMPORARY	},
+		{ "d",	IA_DEPRECATED,		IA_DEPRECATED	},
+		{ NULL,		0,			0	}
+	};
+	fmask_t pflags_mask[] = {
+		{ "U",	IA_UP,			IA_UP		},
+		{ "p",	IA_PRIVATE,		IA_PRIVATE	},
+		{ "d",	IA_DEPRECATED,		IA_DEPRECATED	},
+		{ NULL,		0,			0	}
+	};
+	fmask_t type[] = {
+		{ "static",	IPADM_ADDR_STATIC,	IPADM_ALL_BITS},
+		{ "addrconf",	IPADM_ADDR_IPV6_ADDRCONF, IPADM_ALL_BITS},
+		{ "dhcp",	IPADM_ADDR_DHCP,	IPADM_ALL_BITS},
+		{ NULL,		0,			0	}
+	};
+	fmask_t addr_state[] = {
+		{ "disabled",	IFA_DISABLED,	IPADM_ALL_BITS},
+		{ "duplicate",	IFA_DUPLICATE,	IPADM_ALL_BITS},
+		{ "down",	IFA_DOWN,	IPADM_ALL_BITS},
+		{ "tentative",	IFA_TENTATIVE,	IPADM_ALL_BITS},
+		{ "ok",		IFA_OK,		IPADM_ALL_BITS},
+		{ "inaccessible", IFA_INACCESSIBLE, IPADM_ALL_BITS},
+		{ NULL,		0,		0	}
+	};
+
+	buf[0] = '\0';
+	switch (ofarg->ofmt_id) {
+	case SA_ADDROBJ:
+		if (ainfo->ia_aobjname[0] == '\0') {
+			(void) strncpy(interface, ifa->ifa_name, LIFNAMSIZ);
+			phyname = strrchr(interface, ':');
+			if (phyname)
+				*phyname = '\0';
+			(void) snprintf(buf, bufsize, "%s/%s", interface,
+			    STR_UNKNOWN_VAL);
+		} else {
+			(void) snprintf(buf, bufsize, "%s", ainfo->ia_aobjname);
+		}
+		break;
+	case SA_STATE:
+		flags2str(ainfo->ia_state, addr_state, _B_FALSE,
+		    buf, bufsize);
+		break;
+	case SA_TYPE:
+		flags2str(ainfo->ia_atype, type, _B_FALSE, buf, bufsize);
+		break;
+	case SA_CURRENT:
+		flags2str(ainfo->ia_cflags, cflags_mask, _B_TRUE, buf, bufsize);
+		break;
+	case SA_PERSISTENT:
+		flags2str(ainfo->ia_pflags, pflags_mask, _B_TRUE, buf, bufsize);
+		break;
+	case SA_ADDR:
+		af = ifa->ifa_addr->ss_family;
+		/*
+		 * If the address is 0.0.0.0 or :: and the origin is DHCP,
+		 * print STR_UNKNOWN_VAL.
+		 */
+		if (ainfo->ia_atype == IPADM_ADDR_DHCP) {
+			sin = (struct sockaddr_in *)ifa->ifa_addr;
+			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+			if ((af == AF_INET &&
+			    sin->sin_addr.s_addr == INADDR_ANY) ||
+			    (af == AF_INET6 &&
+			    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))) {
+				(void) snprintf(buf, bufsize, STR_UNKNOWN_VAL);
+				break;
+			}
+		}
+		if (ifa->ifa_netmask == NULL)
+			prefixlen = 0;
+		else
+			prefixlen = mask2plen(ifa->ifa_netmask);
+		bzero(prefixlenstr, sizeof (prefixlenstr));
+		if (prefixlen > 0) {
+			(void) snprintf(prefixlenstr, sizeof (prefixlenstr),
+			    "/%d", prefixlen);
+		}
+		bzero(addrbuf, sizeof (addrbuf));
+		bzero(dstbuf, sizeof (dstbuf));
+		if (ainfo->ia_atype == IPADM_ADDR_STATIC) {
+			/*
+			 * Print the hostname fields if the address is not
+			 * in active configuration.
+			 */
+			if (ainfo->ia_state == IFA_DISABLED) {
+				(void) snprintf(buf, bufsize, "%s",
+				    ainfo->ia_sname);
+				if (ainfo->ia_dname[0] != '\0') {
+					(void) snprintf(dstbuf, sizeof (dstbuf),
+					    "->%s", ainfo->ia_dname);
+					(void) strlcat(buf, dstbuf, bufsize);
+				} else {
+					(void) strlcat(buf, prefixlenstr,
+					    bufsize);
+				}
+				break;
+			}
+			/*
+			 * For the non-persistent case, we need to show the
+			 * currently configured addresses for source and
+			 * destination.
+			 */
+			if (ifa->ifa_flags & IFF_POINTOPOINT) {
+				sockaddr2str(
+				    (struct sockaddr_storage *)ifa->ifa_dstaddr,
+				    dstbuf, sizeof (dstbuf));
+			}
+		}
+		sockaddr2str((struct sockaddr_storage *)ifa->ifa_addr,
+		    addrbuf, sizeof (addrbuf));
+		if (dstbuf[0] != '\0') {
+			(void) snprintf(buf, bufsize, "%s->%s", addrbuf,
+			    dstbuf);
+		} else {
+			(void) snprintf(buf, bufsize, "%s%s", addrbuf,
+			    prefixlenstr);
+		}
+		break;
+	default:
+		die("invalid input");
+		break;
+	}
+
+	return (_B_TRUE);
+}
+
+/*
+ * Display address information, either for the given address or
+ * for all the addresses managed by ipadm.
+ */
+static void
+do_show_addr(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t		status;
+	show_addr_state_t	state;
+	char			*def_fields_str = "addrobj,type,state,addr";
+	char			*fields_str = NULL;
+	ipadm_addr_info_t	*ainfo;
+	ipadm_addr_info_t	*ptr;
+	show_addr_args_t	sargs;
+	int			option;
+	ofmt_handle_t		ofmt;
+	ofmt_status_t		oferr;
+	uint_t			ofmtflags = 0;
+	char			*aname;
+	char			*ifname = NULL;
+	char			*cp;
+	boolean_t		found = _B_FALSE;
+
+	opterr = 0;
+	state.sa_parsable = _B_FALSE;
+	state.sa_persist = _B_FALSE;
+	while ((option = getopt_long(argc, argv, "po:", show_addr_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			state.sa_parsable = _B_TRUE;
+			break;
+		case 'o':
+			fields_str = optarg;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+	if (state.sa_parsable && fields_str == NULL)
+		die("-p requires -o");
+
+	if (optind == argc - 1) {
+		aname = argv[optind];
+		if ((cp = strchr(aname, '/')) == NULL)
+			die("Invalid address object name provided");
+		if (*(cp + 1) == '\0') {
+			ifname = aname;
+			*cp = '\0';
+			aname = NULL;
+		}
+	} else if (optind == argc) {
+		aname = NULL;
+	} else {
+		die("Usage: %s", use);
+	}
+
+	if (state.sa_parsable)
+		ofmtflags |= OFMT_PARSABLE;
+	if (fields_str == NULL)
+		fields_str = def_fields_str;
+	oferr = ofmt_open(fields_str, show_addr_fields, ofmtflags, 0, &ofmt);
+
+	ipadm_ofmt_check(oferr, state.sa_parsable, ofmt);
+	state.sa_ofmt = ofmt;
+
+	status = ipadm_addr_info(iph, ifname, &ainfo, 0, LIFC_DEFAULT);
+	/*
+	 * Return without printing any error, if no addresses were found,
+	 * for the case where all addresses are requested.
+	 */
+	if (status != IPADM_SUCCESS)
+		die("Could not get address: %s", ipadm_status2str(status));
+	if (ainfo == NULL) {
+		ofmt_close(ofmt);
+		return;
+	}
+
+	bzero(&sargs, sizeof (sargs));
+	sargs.sa_state = &state;
+	for (ptr = ainfo; ptr != NULL; ptr = IA_NEXT(ptr)) {
+		sargs.sa_info = ptr;
+		if (aname != NULL) {
+			if (strcmp(sargs.sa_info->ia_aobjname, aname) != 0)
+				continue;
+			found = _B_TRUE;
+		}
+		ofmt_print(state.sa_ofmt, &sargs);
+	}
+	if (ainfo)
+		ipadm_free_addr_info(ainfo);
+	if (aname != NULL && !found)
+		die("Address object not found");
+}
+
+static boolean_t
+print_si_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
+{
+	show_if_args_t		*arg = ofarg->ofmt_cbarg;
+	ipadm_if_info_t		*ifinfo = arg->si_info;
+	char			*ifname = ifinfo->ifi_name;
+	fmask_t intf_state[] = {
+		{ "ok",		IFIS_OK,	IPADM_ALL_BITS},
+		{ "down",	IFIS_DOWN,	IPADM_ALL_BITS},
+		{ "disabled",	IFIS_DISABLED,	IPADM_ALL_BITS},
+		{ "failed",	IFIS_FAILED,	IPADM_ALL_BITS},
+		{ "offline",	IFIS_OFFLINE,	IPADM_ALL_BITS},
+		{ NULL,		0,		0	}
+	};
+	fmask_t intf_pflags[] = {
+		{ "s",	IFIF_STANDBY,		IFIF_STANDBY	},
+		{ "4",	IFIF_IPV4,		IFIF_IPV4	},
+		{ "6",	IFIF_IPV6,		IFIF_IPV6	},
+		{ NULL,	0,			0		}
+	};
+	fmask_t intf_cflags[] = {
+		{ "b",	IFIF_BROADCAST,		IFIF_BROADCAST	},
+		{ "m",	IFIF_MULTICAST,		IFIF_MULTICAST	},
+		{ "p",	IFIF_POINTOPOINT,	IFIF_POINTOPOINT},
+		{ "v",	IFIF_VIRTUAL,		IFIF_VIRTUAL	},
+		{ "I",	IFIF_IPMP,		IFIF_IPMP	},
+		{ "s",	IFIF_STANDBY,		IFIF_STANDBY	},
+		{ "i",	IFIF_INACTIVE,		IFIF_INACTIVE	},
+		{ "V",	IFIF_VRRP,		IFIF_VRRP	},
+		{ "a",	IFIF_NOACCEPT,		IFIF_NOACCEPT	},
+		{ "4",	IFIF_IPV4,		IFIF_IPV4	},
+		{ "6",	IFIF_IPV6,		IFIF_IPV6	},
+		{ NULL,	0,			0		}
+	};
+
+	buf[0] = '\0';
+	switch (ofarg->ofmt_id) {
+	case SI_IFNAME:
+		(void) snprintf(buf, bufsize, "%s", ifname);
+		break;
+	case SI_STATE:
+		flags2str(ifinfo->ifi_state, intf_state, _B_FALSE,
+		    buf, bufsize);
+		break;
+	case SI_CURRENT:
+		flags2str(ifinfo->ifi_cflags, intf_cflags, _B_TRUE,
+		    buf, bufsize);
+		break;
+	case SI_PERSISTENT:
+		flags2str(ifinfo->ifi_pflags, intf_pflags, _B_TRUE,
+		    buf, bufsize);
+		break;
+	default:
+		die("invalid input");
+		break;
+	}
+
+	return (_B_TRUE);
+}
+
+/*
+ * Display interface information, either for the given interface or
+ * for all the interfaces in the system.
+ */
+static void
+do_show_if(int argc, char *argv[], const char *use)
+{
+	ipadm_status_t		status;
+	show_if_state_t		state;
+	char			*fields_str = NULL;
+	ipadm_if_info_t		*if_info, *ptr;
+	show_if_args_t		sargs;
+	int			option;
+	ofmt_handle_t		ofmt;
+	ofmt_status_t		oferr;
+	uint_t			ofmtflags = 0;
+	char			*ifname = NULL;
+
+	opterr = 0;
+	state.si_parsable = _B_FALSE;
+
+	while ((option = getopt_long(argc, argv, "po:", show_if_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			state.si_parsable = _B_TRUE;
+			break;
+		case 'o':
+			fields_str = optarg;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+	if (optind == argc - 1)
+		ifname = argv[optind];
+	else if (optind != argc)
+		die("Usage: %s", use);
+	if (state.si_parsable)
+		ofmtflags |= OFMT_PARSABLE;
+	oferr = ofmt_open(fields_str, show_if_fields, ofmtflags, 0, &ofmt);
+	ipadm_ofmt_check(oferr, state.si_parsable, ofmt);
+	state.si_ofmt = ofmt;
+	bzero(&sargs, sizeof (sargs));
+	sargs.si_state = &state;
+	status = ipadm_if_info(iph, ifname, &if_info, 0, LIFC_DEFAULT);
+	/*
+	 * Return without printing any error, if no addresses were found.
+	 */
+	if (status != IPADM_SUCCESS) {
+		die("Could not get interface(s): %s",
+		    ipadm_status2str(status));
+	}
+
+	for (ptr = if_info; ptr; ptr = ptr->ifi_next) {
+		sargs.si_info = ptr;
+		ofmt_print(state.si_ofmt, &sargs);
+	}
+	if (if_info)
+		ipadm_free_if_info(if_info);
+}
+
+/*
+ * set/reset the address property for a given address
+ */
+static void
+set_addrprop(int argc, char **argv, boolean_t reset, const char *use)
+{
+	int 			option;
+	ipadm_status_t 		status = IPADM_SUCCESS;
+	boolean_t 		p_arg = _B_FALSE;
+	char 			*nv, *aobjname;
+	char			*prop_name, *prop_val;
+	uint_t			flags = IPADM_OPT_ACTIVE|IPADM_OPT_PERSIST;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, ":i:p:t", set_ifprop_longopts,
+	    NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (p_arg)
+				die("-p must be specified once only");
+			p_arg = _B_TRUE;
+
+			ipadm_check_propstr(optarg, reset, use);
+			nv = optarg;
+			break;
+		case 't':
+			flags &= ~IPADM_OPT_PERSIST;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+		}
+	}
+
+	if (!p_arg || optind != (argc - 1))
+		die("Usage: %s", use);
+
+	prop_name = nv;
+	prop_val = strchr(nv, '=');
+	if (prop_val != NULL)
+		*prop_val++ = '\0';
+	aobjname = argv[optind];
+	if (reset)
+		flags |= IPADM_OPT_DEFAULT;
+	status = ipadm_set_addrprop(iph, prop_name, prop_val, aobjname, flags);
+	if (status != IPADM_SUCCESS) {
+		if (reset)
+			die("reset-addrprop: %s: %s", prop_name,
+			    ipadm_status2str(status));
+		else
+			die("set-addrprop: %s: %s", prop_name,
+			    ipadm_status2str(status));
+	}
+}
+
+/*
+ * Sets a property on an address object.
+ */
+static void
+do_set_addrprop(int argc, char **argv, const char *use)
+{
+	set_addrprop(argc, argv, _B_FALSE, use);
+}
+
+/*
+ * Resets a property to its default value on an address object.
+ */
+static void
+do_reset_addrprop(int argc, char **argv, const char *use)
+{
+	set_addrprop(argc, argv,  _B_TRUE, use);
+}
+
+/*
+ * Display information for all or specific address properties, either for a
+ * given address or for all the addresses in the system.
+ */
+static void
+do_show_addrprop(int argc, char *argv[], const char *use)
+{
+	int 			option;
+	nvlist_t 		*proplist = NULL;
+	char			*fields_str = NULL;
+	show_prop_state_t 	state;
+	ofmt_handle_t		ofmt;
+	ofmt_status_t		oferr;
+	uint_t			ofmtflags = 0;
+	char			*aobjname;
+	char			*ifname = NULL;
+	char			*cp;
+
+	opterr = 0;
+	bzero(&state, sizeof (state));
+	state.sps_propval = NULL;
+	state.sps_parsable = _B_FALSE;
+	state.sps_addrprop = _B_TRUE;
+	state.sps_proto = MOD_PROTO_NONE;
+	state.sps_status = state.sps_retstatus = IPADM_SUCCESS;
+	while ((option = getopt_long(argc, argv, ":p:i:cPo:",
+	    show_prop_longopts, NULL)) != -1) {
+		switch (option) {
+		case 'p':
+			if (ipadm_str2nvlist(optarg, &proplist,
+			    IPADM_NORVAL) != 0)
+				die("invalid interface properties specified");
+			break;
+		case 'c':
+			state.sps_parsable = _B_TRUE;
+			break;
+		case 'o':
+			fields_str = optarg;
+			break;
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+	if (optind == argc - 1) {
+		aobjname = argv[optind];
+		cp = strchr(aobjname, '/');
+		if (cp == NULL)
+			die("Invalid address object name provided");
+		if (*(cp + 1) == '\0') {
+			ifname = aobjname;
+			*cp = '\0';
+			aobjname = NULL;
+		}
+	} else if (optind == argc) {
+		aobjname = NULL;
+	} else {
+		die("Usage: %s", use);
+	}
+	state.sps_proplist = proplist;
+	if (state.sps_parsable)
+		ofmtflags |= OFMT_PARSABLE;
+	oferr = ofmt_open(fields_str, addrprop_fields, ofmtflags, 0, &ofmt);
+	ipadm_ofmt_check(oferr, state.sps_parsable, ofmt);
+	state.sps_ofmt = ofmt;
+
+	if (aobjname != NULL) {
+		(void) strlcpy(state.sps_aobjname, aobjname,
+		    sizeof (state.sps_aobjname));
+		show_properties(&state, IPADMPROP_CLASS_ADDR);
+	} else {
+		ipadm_addr_info_t	*ainfop = NULL;
+		ipadm_addr_info_t	*ptr;
+		ipadm_status_t		status;
+
+		status = ipadm_addr_info(iph, ifname, &ainfop, 0, LIFC_DEFAULT);
+		/*
+		 * Return without printing any error, if no addresses were
+		 * found.
+		 */
+		if (status == IPADM_NOTFOUND)
+			return;
+		if (status != IPADM_SUCCESS) {
+			die("Error retrieving address: %s",
+			    ipadm_status2str(status));
+		}
+		for (ptr = ainfop; ptr; ptr = IA_NEXT(ptr)) {
+			aobjname = ptr->ia_aobjname;
+			if (aobjname[0] == '\0' ||
+			    ptr->ia_atype == IPADM_ADDR_IPV6_ADDRCONF) {
+				continue;
+			}
+			(void) strlcpy(state.sps_aobjname, aobjname,
+			    sizeof (state.sps_aobjname));
+			show_properties(&state, IPADMPROP_CLASS_ADDR);
+		}
+		ipadm_free_addr_info(ainfop);
+	}
+	nvlist_free(proplist);
+	ofmt_close(ofmt);
+	if (state.sps_retstatus != IPADM_SUCCESS) {
+		ipadm_close(iph);
+		exit(EXIT_FAILURE);
+	}
+}
+
+static void
+ipadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
+    ofmt_handle_t ofmt)
+{
+	char buf[OFMT_BUFSIZE];
+
+	if (oferr == OFMT_SUCCESS)
+		return;
+	(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
+	/*
+	 * All errors are considered fatal in parsable mode.
+	 * NOMEM errors are always fatal, regardless of mode.
+	 * For other errors, we print diagnostics in human-readable
+	 * mode and processs what we can.
+	 */
+	if (parsable || oferr == OFMT_ENOFIELDS) {
+		ofmt_close(ofmt);
+		die(buf);
+	} else {
+		warn(buf);
+	}
+}
+
+/*
+ * check if the `pstr' adheres to following syntax
+ *	- prop=<value[,...]>	(for set)
+ *	- prop			(for reset)
+ */
+static void
+ipadm_check_propstr(const char *pstr, boolean_t reset, const char *use)
+{
+	char	*nv;
+
+	nv = strchr(pstr, '=');
+	if (reset) {
+		if (nv != NULL)
+			die("incorrect syntax used for -p.\n%s", use);
+	} else {
+		if (nv == NULL || *++nv == '\0')
+			die("please specify the value to be set.\n%s", use);
+		nv = strchr(nv, '=');
+		/* cannot have multiple 'prop=val' for single -p */
+		if (nv != NULL)
+			die("cannot specify more than one prop=val at "
+			    "a time.\n%s", use);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,137 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+msgid  ""
+msgid  "\n"
+msgid  "%s"
+msgid  "%s\n"
+msgid  "%s%s"
+msgid  "%s->%s"
+msgid  "%s/%s"
+msgid  "%s: "
+msgid  "'%s'"
+msgid  "+-"
+msgid  ","
+msgid  "-"
+msgid  "->%s"
+msgid  "/%d"
+msgid  "4"
+msgid  "6"
+msgid  ":T:a:di:p:w:t"
+msgid  ":i"
+msgid  ":i:p:t"
+msgid  ":m:p:t"
+msgid  ":p:co:"
+msgid  ":p:i:cPo:"
+msgid  ":p:m:co:"
+msgid  ":p:t"
+msgid  ":r"
+msgid  ":t"
+msgid  "ADDR"
+msgid  "ADDROBJ"
+msgid  "CURRENT"
+msgid  "DEFAULT"
+msgid  "I"
+msgid  "IFNAME"
+msgid  "PERM"
+msgid  "PERSISTENT"
+msgid  "POSSIBLE"
+msgid  "PROPERTY"
+msgid  "PROTO"
+msgid  "STATE"
+msgid  "TYPE"
+msgid  "U"
+msgid  "V"
+msgid  "a"
+msgid  "addrconf"
+msgid  "address"
+msgid  "addrobj,type,state,addr"
+msgid  "b"
+msgid  "create-addr"
+msgid  "create-if"
+msgid  "d"
+msgid  "delete-addr"
+msgid  "delete-if"
+msgid  "dhcp"
+msgid  "disable-addr"
+msgid  "disable-if"
+msgid  "disabled"
+msgid  "down"
+msgid  "down-addr"
+msgid  "duplicate"
+msgid  "enable-addr"
+msgid  "enable-if"
+msgid  "failed"
+msgid  "forever"
+msgid  "i"
+msgid  "inaccessible"
+msgid  "inform"
+msgid  "init-if"
+msgid  "init-prop"
+msgid  "interface-id"
+msgid  "ip"
+msgid  "local"
+msgid  "m"
+msgid  "module"
+msgid  "no"
+msgid  "offline"
+msgid  "ok"
+msgid  "output"
+msgid  "p"
+msgid  "parsable"
+msgid  "po:"
+msgid  "prop"
+msgid  "refresh-addr"
+msgid  "release"
+msgid  "remote"
+msgid  "reset-addrprop"
+msgid  "reset-addrprop: %s: %s"
+msgid  "reset-ifprop"
+msgid  "reset-ifprop: %s: %s"
+msgid  "reset-prop"
+msgid  "reset-prop: %s: %s"
+msgid  "s"
+msgid  "set-addrprop"
+msgid  "set-addrprop: %s: %s"
+msgid  "set-ifprop"
+msgid  "set-ifprop: %s: %s"
+msgid  "set-prop"
+msgid  "set-prop: %s: %s"
+msgid  "show-addr"
+msgid  "show-addrprop"
+msgid  "show-if"
+msgid  "show-ifprop"
+msgid  "show-prop"
+msgid  "stateful"
+msgid  "stateless"
+msgid  "static"
+msgid  "t"
+msgid  "temporary"
+msgid  "tentative"
+msgid  "type"
+msgid  "u"
+msgid  "up-addr"
+msgid  "v"
+msgid  "wait"
+msgid  "yes"
--- a/usr/src/cmd/cmd-inet/usr.sbin/ndd.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ndd.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,11 +36,14 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <stropts.h>
+#include <inet/tunables.h>
 #include <inet/nd.h>
 #include <string.h>
+#include <strings.h>
 #include <stdlib.h>
 #include <libdllink.h>
 #include <libintl.h>
+#include <libipadm.h>
 
 static boolean_t do_getset(int fd, int cmd, char *buf, int buf_len);
 static int	get_value(char *msg, char *buf, int buf_len);
@@ -51,11 +54,259 @@
 static void	fatal(char *fmt, ...);
 static void	printe(boolean_t print_errno, char *fmt, ...);
 
-static char	gbuf[65536];	/* Need 20k for 160 IREs ... */
+static char	modpath[128];	/* path to module */
+static char	gbuf[65536];	/* need large buffer to retrieve all names */
 static char	usage_str[] =	"usage: ndd -set device_name name value\n"
 				"       ndd [-get] device_name name [name ...]";
 
 /*
+ * Maps old ndd_name to the new ipadm_name. Any ndd property that is moved to
+ * libipadm should have an entry here to ensure backward compatibility
+ */
+typedef struct ndd2ipadm_map {
+	char	*ndd_name;
+	char	*ipadm_name;
+	uint_t	ipadm_proto;
+	uint_t	ipadm_flags;
+	uint_t	ndd_perm;
+} ndd2ipadm_map_t;
+
+static ndd2ipadm_map_t map[] = {
+	{ "ip_def_ttl",			"ttl",		MOD_PROTO_IPV4, 0, 0 },
+	{ "ip6_def_hops",		"hoplimit",	MOD_PROTO_IPV6, 0, 0 },
+	{ "ip_forwarding",		"forwarding",	MOD_PROTO_IPV4, 0, 0 },
+	{ "ip6_forwarding",		"forwarding",	MOD_PROTO_IPV6, 0, 0 },
+	{ "icmp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
+	{ "icmp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_RAWIP, 0, 0 },
+	{ "tcp_ecn_permitted",		"ecn",		MOD_PROTO_TCP, 0, 0 },
+	{ "tcp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_TCP,
+	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
+	{ "tcp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_TCP,
+	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
+	{ "tcp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_TCP,
+	    0, MOD_PROP_PERM_READ },
+	{ "tcp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_TCP,
+	    0, 0 },
+	{ "tcp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_TCP, 0, 0 },
+	{ "tcp_sack_permitted",		"sack",		MOD_PROTO_TCP, 0, 0 },
+	{ "tcp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_TCP, 0, 0 },
+	{ "tcp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_TCP,
+	    0, 0 },
+	{ "tcp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_TCP,
+	    0, 0 },
+	{ "udp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_UDP,
+	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
+	{ "udp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_UDP,
+	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
+	{ "udp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_UDP,
+	    0, MOD_PROP_PERM_READ },
+	{ "udp_largest_anon_port",	"largest_anon_port",    MOD_PROTO_UDP,
+	    0, 0 },
+	{ "udp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_UDP, 0, 0 },
+	{ "udp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_UDP, 0, 0 },
+	{ "udp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_UDP,
+	    0, 0 },
+	{ "udp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_UDP,
+	    0, 0 },
+	{ "sctp_extra_priv_ports_add",	"extra_priv_ports",	MOD_PROTO_SCTP,
+	    IPADM_OPT_APPEND, MOD_PROP_PERM_WRITE },
+	{ "sctp_extra_priv_ports_del",	"extra_priv_ports",	MOD_PROTO_SCTP,
+	    IPADM_OPT_REMOVE, MOD_PROP_PERM_WRITE },
+	{ "sctp_extra_priv_ports",	"extra_priv_ports",	MOD_PROTO_SCTP,
+	    0, MOD_PROP_PERM_READ },
+	{ "sctp_largest_anon_port",	"largest_anon_port",	MOD_PROTO_SCTP,
+	    0, 0 },
+	{ "sctp_recv_hiwat",		"recv_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
+	{ "sctp_xmit_hiwat",		"send_maxbuf",	MOD_PROTO_SCTP, 0, 0 },
+	{ "sctp_smallest_anon_port",	"smallest_anon_port",	MOD_PROTO_SCTP,
+	    0, 0 },
+	{ "sctp_smallest_nonpriv_port",	"smallest_nonpriv_port", MOD_PROTO_SCTP,
+	    0, 0 },
+	{ NULL, NULL, 0, 0, 0 }
+};
+
+static uint_t
+ndd_str2proto(const char *protostr)
+{
+	if (strcmp(protostr, "tcp") == 0 ||
+	    strcmp(protostr, "tcp6") == 0) {
+		return (MOD_PROTO_TCP);
+	} else if (strcmp(protostr, "udp") == 0 ||
+	    strcmp(protostr, "udp6") == 0) {
+		return (MOD_PROTO_UDP);
+	} else if (strcmp(protostr, "ip") == 0 ||
+	    strcmp(protostr, "ip6") == 0 ||
+	    strcmp(protostr, "arp") == 0) {
+		return (MOD_PROTO_IP);
+	} else if (strcmp(protostr, "icmp") == 0 ||
+	    strcmp(protostr, "icmp6") == 0) {
+		return (MOD_PROTO_RAWIP);
+	} else if (strcmp(protostr, "sctp") == 0 ||
+	    strcmp(protostr, "sctp6") == 0) {
+		return (MOD_PROTO_SCTP);
+	}
+	return (MOD_PROTO_NONE);
+}
+
+static char *
+ndd_perm2str(uint_t perm)
+{
+	switch (perm) {
+	case MOD_PROP_PERM_READ:
+		return ("read only");
+	case MOD_PROP_PERM_WRITE:
+		return ("write only");
+	case MOD_PROP_PERM_RW:
+		return ("read and write");
+	}
+
+	return (NULL);
+}
+
+/*
+ * This function converts any new property names to old ndd name by consulting
+ * ndd2ipadm_map_t. This is done to preserve backward compatibility.
+ */
+static void
+print_ipadm2ndd(char *oldbuf, uint_t obufsize)
+{
+	ndd2ipadm_map_t	*nimap;
+	char		*pname, *rwtag, *protostr;
+	uint_t		proto, perm;
+	boolean_t	matched;
+
+	pname = oldbuf;
+	while (pname[0] && pname < (oldbuf + obufsize - 1)) {
+		for (protostr = pname; !isspace(*protostr); protostr++)
+			;
+		*protostr++ = '\0';
+		/* protostr now points to protocol */
+
+		for (rwtag = protostr; !isspace(*rwtag); rwtag++)
+			;
+		*rwtag++ = '\0';
+		/* rwtag now points to permissions */
+
+		proto = atoi(protostr);
+		perm = atoi(rwtag);
+		matched = B_FALSE;
+		for (nimap = map; nimap->ndd_name != NULL; nimap++) {
+			if (strcmp(pname, nimap->ipadm_name) != 0 ||
+			    !(nimap->ipadm_proto & proto))
+				continue;
+
+			matched = B_TRUE;
+			if (nimap->ndd_perm != 0)
+				perm = nimap->ndd_perm;
+			(void) printf("%-30s (%s)\n", nimap->ndd_name,
+			    ndd_perm2str(perm));
+		}
+		if (!matched)
+			(void) printf("%-30s (%s)\n", pname,
+			    ndd_perm2str(perm));
+		for (pname = rwtag; *pname++; )
+			;
+	}
+}
+
+/*
+ * get/set the value for a given property by calling into libipadm. The
+ * IPH_LEGACY flag is used by libipadm for special handling. For some
+ * properties, libipadm.so displays strings (for e.g., on/off,
+ * never/passive/active, et al) instead of numerals. However ndd(1M) always
+ * printed numberals. This flag will help in avoiding printing strings.
+ */
+static boolean_t
+do_ipadm_getset(int cmd, char *buf, int buflen)
+{
+	ndd2ipadm_map_t	*nimap;
+	ipadm_handle_t	iph = NULL;
+	ipadm_status_t	status;
+	char		*mod;
+	uint_t		proto, perm = 0, flags = 0;
+	char		*pname, *pvalp;
+	int		i;
+
+	if ((mod = strrchr(modpath, '/')) == NULL)
+		mod = modpath;
+	else
+		++mod;
+	if ((proto = ndd_str2proto(mod)) == MOD_PROTO_NONE)
+		return (B_FALSE);
+
+	if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS)
+		goto fail;
+
+	pname = buf;
+	for (nimap = map; nimap->ndd_name != NULL; nimap++) {
+		if (strcmp(pname, nimap->ndd_name) == 0)
+			break;
+	}
+	if (nimap->ndd_name != NULL) {
+		pname = nimap->ipadm_name;
+		proto = nimap->ipadm_proto;
+		flags = nimap->ipadm_flags;
+		perm = nimap->ndd_perm;
+	}
+	if (cmd == ND_GET) {
+		char		propval[MAXPROPVALLEN], allprop[64536];
+		uint_t		pvalsz;
+		sa_family_t	af = AF_UNSPEC;
+		int		err;
+
+		if (perm == MOD_PROP_PERM_WRITE)
+			fatal("operation failed: Permission denied");
+
+		if (strcmp(pname, "?") == 0) {
+			pvalp = allprop;
+			pvalsz = sizeof (allprop);
+		} else {
+			pvalp = propval;
+			pvalsz = sizeof (propval);
+		}
+
+		status = ipadm_get_prop(iph, pname, pvalp, &pvalsz, proto,
+		    IPADM_OPT_ACTIVE);
+		if (status != IPADM_SUCCESS)
+			goto fail;
+
+		if (strcmp(pname, "?") == 0) {
+			(void) print_ipadm2ndd(pvalp, pvalsz);
+		} else {
+			char *tmp = pvalp;
+
+			/*
+			 * For backward compatibility if there are multiple
+			 * values print each value in it's own line.
+			 */
+			while (*tmp != '\0') {
+				if (*tmp == ',')
+					*tmp = '\n';
+				tmp++;
+			}
+			(void) printf("%s\n", pvalp);
+		}
+		(void) fflush(stdout);
+	} else {
+		if (perm == MOD_PROP_PERM_READ)
+			fatal("operation failed: Permission denied");
+
+		/* walk past the property name to find the property value */
+		for (i = 0; buf[i] != '\0'; i++)
+			;
+
+		pvalp = &buf[++i];
+		status = ipadm_set_prop(iph, pname, pvalp, proto,
+		    flags|IPADM_OPT_ACTIVE);
+	}
+fail:
+	ipadm_close(iph);
+	if (status != IPADM_SUCCESS)
+		fatal("operation failed: %s", ipadm_status2str(status));
+	return (B_TRUE);
+}
+
+/*
  * gldv3_warning() catches the case of /sbin/ndd abuse to administer
  * ethernet/MII props. Note that /sbin/ndd has not been abused
  * for administration of other datalink types, which makes it permissible
@@ -98,10 +349,9 @@
 int
 main(int argc, char **argv)
 {
-	char	*cp, *value;
+	char	*cp, *value, *mod;
 	int	cmd;
-	int	fd;
-
+	int	fd = 0;
 
 	if (!(cp = *++argv)) {
 		while ((fd = open_device()) != -1) {
@@ -120,14 +370,23 @@
 		if (!(cp = *++argv))
 			fatal(usage_str);
 	}
+
 	gldv3_warning(cp);
 
-	if ((fd = open(cp, O_RDWR)) == -1)
-		fatal("open of %s failed: %s", cp, errmsg(errno));
+	mod = strrchr(cp, '/');
+	if (mod != NULL)
+		mod++;
+	else
+		mod = cp;
 
-	if (!isastream(fd))
-		fatal("%s is not a streams device", cp);
+	if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
+		if ((fd = open(cp, O_RDWR)) == -1)
+			fatal("open of %s failed: %s", cp, errmsg(errno));
+		if (!isastream(fd))
+			fatal("%s is not a streams device", cp);
+	}
 
+	(void) strlcpy(modpath, cp, sizeof (modpath));
 	if (!(cp = *++argv)) {
 		getset_interactive(fd);
 		(void) close(fd);
@@ -199,6 +458,13 @@
 	if (is_obsolete(buf))
 		return (B_TRUE);
 
+	/*
+	 * See if libipadm can handle this request, i.e., properties on
+	 * following modules arp, ip, ipv4, ipv6, tcp, udp and sctp
+	 */
+	if (do_ipadm_getset(cmd, buf, buf_len))
+		return (B_TRUE);
+
 	stri.ic_cmd = cmd;
 	stri.ic_timout = 0;
 	stri.ic_len = buf_len;
@@ -293,31 +559,40 @@
 		(void) printf("\n");
 }
 
-
 static int
 open_device()
 {
-	char	name[80];
 	int	fd, len;
+	char	*mod;
 
 	for (;;) {
-		len = get_value("module to query ? ", name, sizeof (name));
+		len = get_value("module to query ? ", modpath,
+		    sizeof (modpath));
 		if (len <= 1 ||
-		    (len == 2 && (name[0] == 'q' || name[0] == 'Q')))
+		    (len == 2 && (modpath[0] == 'q' || modpath[0] == 'Q')))
 			return (-1);
 
-		if ((fd = open(name, O_RDWR)) == -1) {
-			printe(B_TRUE, "open of %s failed", name);
-			continue;
+		mod = strrchr(modpath, '/');
+		if (mod != NULL)
+			mod++;
+		else
+			mod = modpath;
+		if (ndd_str2proto(mod) == MOD_PROTO_NONE) {
+			if ((fd = open(modpath, O_RDWR)) == -1) {
+				printe(B_TRUE, "open of %s failed", modpath);
+				continue;
+			}
+		} else {
+			return (0);
 		}
 
-		gldv3_warning(name);
+		gldv3_warning(modpath);
 
 		if (isastream(fd))
 			return (fd);
 
 		(void) close(fd);
-		printe(B_FALSE, "%s is not a streams device", name);
+		printe(B_FALSE, "%s is not a streams device", modpath);
 	}
 }
 
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding	Fri Mar 26 17:53:11 2010 -0400
@@ -20,31 +20,15 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 # This script is the shared method script for the ipv4-routing, ipv6-routing,
 # ipv4-forwarding and ipv6-forwarding services.
 
 . /lib/svc/share/smf_include.sh
 
-set_forwarding_flag() {
-	proto="$1"
-	value="$2"
-	ndd_flag="0"
-	if [ "$value" = "enabled" ]; then
-		ndd_flag="1"
-	fi
-	if [ "$proto" = "ipv4" ]; then
-		/usr/sbin/ndd -set /dev/ip ip_forwarding $ndd_flag
-	else
-		/usr/sbin/ndd -set /dev/ip ip6_forwarding $ndd_flag
-		/usr/sbin/ndd -set /dev/ip ip6_send_redirects $ndd_flag
-	fi
-}
-
 usage() {
 	echo "Usage: $0 { start | stop | refresh } { ipv4 | ipv6 }"
 }
@@ -65,18 +49,19 @@
 	#
 	# Start ip forwarding.
 	#
-	if [ -z "$proto" ]; then
-		usage
-		exit $SMF_ERROR_FATAL
-	fi
 	if [ "$proto" = "ipv6" -a "$numv6ifs" = 0 ]; then
 		echo "Error: no IPv6 interface configured"
 		exit $SMF_EXIT_ERR_CONFIG
 	fi
-	set_forwarding_flag $proto enabled
+
+	/usr/sbin/ipadm set-prop -p forwarding=on $proto
+	[ "$proto" = "ipv6" ] && /usr/sbin/ipadm set-prop \
+				    -p ip6_send_redirects=1 ip
         ;;
 'stop')
-	set_forwarding_flag $proto disabled
+	/usr/sbin/ipadm set-prop -p forwarding=off $proto
+	[ "$proto" = "ipv6" ] && /usr/sbin/ipadm set-prop \
+				    -p ip6_send_redirects=0 ip
 	;;
 *)
 	usage
--- a/usr/src/cmd/rcm_daemon/Makefile.com	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/rcm_daemon/Makefile.com	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -129,7 +129,7 @@
 SUNW_vlan_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
 SUNW_vnic_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
 SUNW_aggr_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
-SUNW_ip_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil -ldladm -lipmp
+SUNW_ip_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil -ldladm -lipmp -lipadm
 SUNW_ip_anon_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -linetutil
 SUNW_bridge_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
 
--- a/usr/src/cmd/rcm_daemon/common/ip_rcm.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/rcm_daemon/common/ip_rcm.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -53,6 +53,7 @@
 #include <libdllink.h>
 #include <libgen.h>
 #include <ipmp_admin.h>
+#include <libipadm.h>
 
 #include "rcm_module.h"
 
@@ -157,6 +158,7 @@
 static int		events_registered = 0;
 
 static dladm_handle_t	dld_handle = NULL;
+static ipadm_handle_t	ip_handle = NULL;
 
 /*
  * RCM module interface prototypes
@@ -186,7 +188,7 @@
 static void 	free_node(ip_cache_t *);
 static void 	cache_insert(ip_cache_t *);
 static char 	*ip_usage(ip_cache_t *);
-static int 	update_pif(rcm_handle_t *, int, int, struct lifreq *);
+static int 	update_pif(rcm_handle_t *, int, int, struct ifaddrs *);
 static int 	ip_ipmp_offline(ip_cache_t *);
 static int	ip_ipmp_undo_offline(ip_cache_t *);
 static int	if_cfginfo(ip_cache_t *, uint_t);
@@ -209,7 +211,9 @@
 			uint_t, rcm_info_t **);
 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
 
-static int if_configure(datalink_id_t);
+static int if_configure_hostname(datalink_id_t);
+static int if_configure_ipadm(datalink_id_t);
+static boolean_t if_hostname_exists(char *, sa_family_t);
 static boolean_t isgrouped(const char *);
 static int if_config_inst(const char *, FILE *, int, boolean_t);
 static uint_t ntok(const char *cp);
@@ -240,6 +244,7 @@
 {
 	char errmsg[DLADM_STRSIZE];
 	dladm_status_t status;
+	ipadm_status_t iph_status;
 
 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
 
@@ -256,6 +261,15 @@
 		return (NULL);
 	}
 
+	if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) {
+		rcm_log_message(RCM_ERROR,
+		    "IP: mod_init failed: cannot get IP handle: %s\n",
+		    ipadm_status2str(iph_status));
+		dladm_close(dld_handle);
+		dld_handle = NULL;
+		return (NULL);
+	}
+
 	/* Return the ops vectors */
 	return (&ip_ops);
 }
@@ -283,6 +297,7 @@
 	(void) mutex_destroy(&cache_lock);
 
 	dladm_close(dld_handle);
+	ipadm_close(ip_handle);
 	return (RCM_SUCCESS);
 }
 
@@ -758,7 +773,25 @@
 				return (RCM_FAILURE);
 			}
 			linkid = (datalink_id_t)id64;
-			if (if_configure(linkid) != 0) {
+			/*
+			 * Grovel through /etc/hostname* files and configure
+			 * interface in the same way that they would be handled
+			 * by network/physical.
+			 */
+			if (if_configure_hostname(linkid) != 0) {
+				rcm_log_message(RCM_ERROR,
+				    _("IP: Configuration failed (%u)\n"),
+				    linkid);
+				ip_log_err(NULL, errorp,
+				    "Failed configuring one or more IP "
+				    "addresses");
+			}
+
+			/*
+			 * Query libipadm for persistent configuration info
+			 * and resurrect that persistent configuration.
+			 */
+			if (if_configure_ipadm(linkid) != 0) {
 				rcm_log_message(RCM_ERROR,
 				    _("IP: Configuration failed (%u)\n"),
 				    linkid);
@@ -1018,9 +1051,8 @@
  * update_pif() - Update physical interface properties
  *		Call with cache_lock held
  */
-/*ARGSUSED*/
-static int
-update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
+int
+update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
 {
 	char *rsrc;
 	ifspec_t ifspec;
@@ -1034,11 +1066,11 @@
 	uint64_t ifflags;
 	int lif_listed = 0;
 
-	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name);
+	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
 
-	if (!ifparse_ifspec(lifr->lifr_name, &ifspec)) {
+	if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
-		    lifr->lifr_name);
+		    ifa->ifa_name);
 		return (-1);
 	}
 
@@ -1048,16 +1080,7 @@
 		ifnumber = ifspec.ifsp_lun;
 
 	/* Get the interface flags */
-	(void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ);
-	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
-		if (errno != ENXIO) {
-			rcm_log_message(RCM_ERROR,
-			    _("IP: SIOCGLIFFLAGS(%s): %s\n"),
-			    lifreq.lifr_name, strerror(errno));
-		}
-		return (-1);
-	}
-	(void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags));
+	ifflags = ifa->ifa_flags;
 
 	/*
 	 * Ignore interfaces that are always incapable of DR:
@@ -1077,6 +1100,9 @@
 	}
 
 	/* Get the interface group name for this interface */
+	bzero(&lifreq, sizeof (lifreq));
+	(void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
+
 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
 		if (errno != ENXIO) {
 			rcm_log_message(RCM_ERROR,
@@ -1091,15 +1117,7 @@
 	    sizeof (pif.pi_grname));
 
 	/* Get the interface address for this interface */
-	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
-		if (errno != ENXIO) {
-			rcm_log_message(RCM_ERROR,
-			    _("IP: SIOCGLIFADDR(%s): %s\n"),
-			    lifreq.lifr_name, strerror(errno));
-			return (-1);
-		}
-	}
-	(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
+	ifaddr = *(ifa->ifa_addr);
 
 	rsrc = get_link_resource(pif.pi_ifname);
 	if (rsrc == NULL) {
@@ -1220,14 +1238,12 @@
 static int
 update_ipifs(rcm_handle_t *hd, int af)
 {
+
+	struct ifaddrs *ifa;
+	ipadm_addr_info_t *ainfo;
+	ipadm_addr_info_t *ptr;
+	ipadm_status_t status;
 	int sock;
-	char *buf;
-	struct lifnum lifn;
-	struct lifconf lifc;
-	struct lifreq *lifrp;
-	int i;
-
-	rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
 
 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
 		rcm_log_message(RCM_ERROR,
@@ -1236,46 +1252,20 @@
 		return (-1);
 	}
 
-	lifn.lifn_family = af;
-	lifn.lifn_flags = LIFC_UNDER_IPMP;
-	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
-		rcm_log_message(RCM_ERROR,
-		    _("IP: SIOCLGIFNUM failed: %s\n"),
-		    strerror(errno));
-		(void) close(sock);
-		return (-1);
-	}
-
-	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
-		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
-		    strerror(errno));
+	status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
+	    LIFC_UNDER_IPMP);
+	if (status != IPADM_SUCCESS) {
 		(void) close(sock);
 		return (-1);
 	}
-
-	lifc.lifc_family = af;
-	lifc.lifc_flags = LIFC_UNDER_IPMP;
-	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
-	lifc.lifc_buf = buf;
-
-	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
-		rcm_log_message(RCM_ERROR,
-		    _("IP: SIOCGLIFCONF failed: %s\n"),
-		    strerror(errno));
-		free(buf);
-		(void) close(sock);
-		return (-1);
+	for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
+		ifa = &ptr->ia_ifa;
+		if (ptr->ia_state != IFA_DISABLED &&
+		    af == ifa->ifa_addr->ss_family)
+			(void) update_pif(hd, af, sock, ifa);
 	}
-
-	/* now we need to search for active interfaces */
-	lifrp = lifc.lifc_req;
-	for (i = 0; i < lifn.lifn_count; i++) {
-		(void) update_pif(hd, af, sock, lifrp);
-		lifrp++;
-	}
-
-	free(buf);
 	(void) close(sock);
+	ipadm_free_addr_info(ainfo);
 	return (0);
 }
 
@@ -2270,20 +2260,15 @@
 }
 
 /*
- * if_configure() - Configure a physical interface after attach
+ * Gets the interface name for the given linkid. Returns -1 if there is
+ * any error. It fills in the interface name in `ifinst' if the interface
+ * is not already configured. Otherwise, it puts a null string in `ifinst'.
  */
 static int
-if_configure(datalink_id_t linkid)
+if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
 {
-	char ifinst[MAXLINKNAMELEN];
-	char cfgfile[MAXPATHLEN];
 	char cached_name[RCM_LINK_RESOURCE_MAX];
-	FILE *hostfp, *host6fp;
 	ip_cache_t *node;
-	boolean_t ipmp = B_FALSE;
-
-	assert(linkid != DATALINK_INVALID_LINKID);
-	rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid);
 
 	/* Check for the interface in the cache */
 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
@@ -2296,16 +2281,42 @@
 		rcm_log_message(RCM_TRACE1,
 		    _("IP: Skipping configured interface(%u)\n"), linkid);
 		(void) mutex_unlock(&cache_lock);
+		*ifinst = '\0';
 		return (0);
 	}
 	(void) mutex_unlock(&cache_lock);
 
 	if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
-	    sizeof (ifinst)) != DLADM_STATUS_OK) {
+	    len) != DLADM_STATUS_OK) {
 		rcm_log_message(RCM_ERROR,
 		    _("IP: get %u link name failed\n"), linkid);
 		return (-1);
 	}
+	return (0);
+}
+
+/*
+ * if_configure_hostname() - Configure a physical interface after attach
+ * based on the information in /etc/hostname.*
+ */
+static int
+if_configure_hostname(datalink_id_t linkid)
+{
+	FILE *hostfp, *host6fp;
+	boolean_t ipmp = B_FALSE;
+	char ifinst[MAXLINKNAMELEN];
+	char cfgfile[MAXPATHLEN];
+
+	assert(linkid != DATALINK_INVALID_LINKID);
+	rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
+	    linkid);
+
+	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
+		return (-1);
+
+	/* Check if the interface is already configured. */
+	if (ifinst[0] == '\0')
+		return (0);
 
 	/*
 	 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
@@ -2344,7 +2355,8 @@
 
 	(void) fclose(hostfp);
 	(void) fclose(host6fp);
-	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst);
+	rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
+	    ifinst);
 	return (0);
 fail:
 	(void) fclose(hostfp);
@@ -2353,6 +2365,76 @@
 }
 
 /*
+ * if_configure_ipadm() - Configure a physical interface after attach
+ * Queries libipadm for persistent configuration information and then
+ * resurrects that persistent configuration.
+ */
+static int
+if_configure_ipadm(datalink_id_t linkid)
+{
+	char ifinst[MAXLINKNAMELEN];
+	boolean_t found;
+	ipadm_if_info_t *ifinfo, *ptr;
+	ipadm_status_t status;
+
+	assert(linkid != DATALINK_INVALID_LINKID);
+	rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
+	    linkid);
+
+	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
+		return (-1);
+
+	/* Check if the interface is already configured. */
+	if (ifinst[0] == '\0')
+		return (0);
+
+	status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
+	if (status == IPADM_ENXIO)
+		goto done;
+	if (status != IPADM_SUCCESS) {
+		rcm_log_message(RCM_ERROR,
+		    _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
+		    ifinst, ipadm_status2str(status));
+		goto fail;
+	}
+	if (ifinfo != NULL) {
+		found = B_FALSE;
+		for (ptr = ifinfo; ptr; ptr = ptr->ifi_next) {
+			if (strncmp(ptr->ifi_name, ifinst,
+			    sizeof (ifinst)) == 0) {
+				found = B_TRUE;
+				break;
+			}
+		}
+		free(ifinfo);
+		if (!found) {
+			return (0);
+		}
+		if (if_hostname_exists(ifinst, AF_INET) ||
+		    if_hostname_exists(ifinst, AF_INET6)) {
+			rcm_log_message(RCM_WARNING,
+			    _("IP: IPv4 Post-attach (%s) found both "
+			    "/etc/hostname and ipadm persistent configuration. "
+			    "Ignoring ipadm config\n"), ifinst);
+			return (0);
+		}
+		status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE);
+		if (status != IPADM_SUCCESS) {
+			rcm_log_message(RCM_ERROR,
+			    _("IP: Post-attach failed (%s) Error %s\n"),
+			    ifinst, ipadm_status2str(status));
+			goto fail;
+		}
+	}
+done:
+	rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
+	    ifinst);
+	return (0);
+fail:
+	return (-1);
+}
+
+/*
  * isgrouped() - Scans the given config file to see if this interface is
  *	         using IPMP.  Returns B_TRUE or B_FALSE.
  */
@@ -2662,3 +2744,23 @@
 	}
 	return (B_TRUE);
 }
+
+/*
+ * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
+ */
+static boolean_t
+if_hostname_exists(char *ifname, sa_family_t af)
+{
+	char cfgfile[MAXPATHLEN];
+
+	if (af == AF_INET) {
+		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
+		if (access(cfgfile, W_OK|F_OK) == 0)
+			return (B_TRUE);
+	} else if (af == AF_INET6) {
+		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
+		if (access(cfgfile, W_OK|F_OK) == 0)
+			return (B_TRUE);
+	}
+	return (B_FALSE);
+}
--- a/usr/src/cmd/svc/milestone/net-iptun	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/svc/milestone/net-iptun	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # This service configures IP tunnel links and IP interfaces over IP
@@ -97,6 +97,26 @@
 		if [ -f /etc/hostname6.$intf_name ]; then
 			plumb_tunnel $intf_name inet6 /etc/hostname6.$intf_name
 		fi
+		#
+		# Configure IP tunnel interfaces set up using ipadm
+		#
+		state=`/sbin/ipadm show-if -p -o state $intf_name`
+		if [ $? -ne 0 ] || [ "$state" != "disabled" ]; then
+			#
+			# skip if not managed my ipadm or if not a persistent
+			# interface
+			#
+			continue;
+		elif [ -f /etc/hostname.$intf_name ] ||\
+			[ -f /etc/hostname6.$intf_name ]; then
+			echo "found /etc/hostname.$intf_name or "\
+			    "/etc/hostname6.$intfi_name, ignoring ipadm "\
+			    "configuration" > /dev/msglog
+			continue;
+		else
+			# Enable the interface managed by ipadm
+			/sbin/ipadm enable-if -t $intf_name
+		fi
 	done
 
 	#
@@ -124,6 +144,7 @@
 	for tun in $tunnel_links; do
 		/sbin/ifconfig $tun unplumb > /dev/null 2>&1
 		/sbin/ifconfig $tun inet6 unplumb > /dev/null 2>&1
+		/sbin/ipadm disable-if -t $tun > /dev/null 2>&1
 	done
 
 	# Take down the IP tunnel links
--- a/usr/src/cmd/svc/milestone/net-loopback	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/svc/milestone/net-loopback	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -34,26 +34,40 @@
 #
 smf_configure_ip || exit $SMF_EXIT_OK
 
-#
-# Before any interfaces are configured, we need to set the system
-# default IP forwarding behavior.  This will be the setting for
-# interfaces that don't modify the per-interface setting with the
-# router or -router ifconfig command in their /etc/hostname.<intf>
-# files.  Due to their dependency on this service, the IP forwarding services
-# will run at this point (though routing daemons will not run until later
-# in the boot process) and set forwarding flags.
-#
+if [ -f /etc/hostname.lo0 ] || [ -f /etc/hostname6.lo0 ]; then
+	echo "found /etc/hostname.lo0 or /etc/hostname6.lo0; "\
+		    "using ifconfig to create lo0" > /dev/msglog
+	# IPv4 loopback
+	/sbin/ifconfig lo0 plumb 127.0.0.1 up
+
+	# IPv6 loopback
+	/sbin/ifconfig lo0 inet6 plumb ::1 up
 
-# IPv4 loopback
-/sbin/ifconfig lo0 plumb 127.0.0.1 up
-
-# IPv6 loopback
-/sbin/ifconfig lo0 inet6 plumb ::1 up
+	# Trusted Extensions shares the loopback interface with all zones
+	if (smf_is_system_labeled); then
+		if smf_is_globalzone; then
+			/sbin/ifconfig lo0 all-zones
+			/sbin/ifconfig lo0 inet6 all-zones
+		fi
+	fi
+else
+	state=`/sbin/ipadm show-if -p -o state lo0 2>/dev/null`
+	if [ $? -eq 0 -a "$state" = "disabled" ]; then
+		/sbin/ipadm enable-if -t lo0
+	else
+		# IPv4 loopback
+		/sbin/ipadm create-addr -t -T static -a 127.0.0.1/8 lo0/v4
 
-# Trusted Extensions shares the loopback interface with all zones
-if (smf_is_system_labeled); then
-	if smf_is_globalzone; then
-		 /sbin/ifconfig lo0 all-zones
-		 /sbin/ifconfig lo0 inet6 all-zones
+		# IPv6 loopback
+		/sbin/ipadm create-addr -t -T static -a ::1/128 lo0/v6
+	fi
+
+	# Trusted Extensions shares the loopback interface with all zones
+	if (smf_is_system_labeled); then
+		if smf_is_globalzone; then
+			/sbin/ipadm set-addrprop -t -p zone=all-zones lo0/v4
+			/sbin/ipadm set-addrprop -t -p zone=all-zones lo0/v6
+		fi
 	fi
 fi
+
--- a/usr/src/cmd/svc/milestone/net-physical	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/svc/milestone/net-physical	Fri Mar 26 17:53:11 2010 -0400
@@ -38,6 +38,7 @@
 #
 smf_configure_ip || exit $SMF_EXIT_OK
 
+
 # Make sure that the libraries essential to this stage of booting can be found.
 LD_LIBRARY_PATH=/lib; export LD_LIBRARY_PATH
 
@@ -138,6 +139,8 @@
 #
 
 #
+# First deal with /etc/hostname
+#
 # Get the list of IPv4 interfaces to configure by breaking
 # /etc/hostname.* into separate args by using "." as a shell separator
 # character.
@@ -289,6 +292,28 @@
 fi
 
 #
+# Finally configure interfaces set up with ipadm.
+#
+for showif_output in `/sbin/ipadm show-if -p -o ifname,state`; do
+	intf=`echo $showif_output | /usr/bin/cut -f1 -d:`
+	state=`echo $showif_output | /usr/bin/cut -f2 -d:`
+	if  [ "$state" != "disabled" ]; then
+		# skip if not a persistent interface
+		continue;
+	elif is_iptun $intf; then
+		# skip IP tunnel interfaces plumbed by net-iptun
+		continue;
+	elif [ -f /etc/hostname.$intf ] || [ -f /etc/hostname6.$intf ]; then
+		echo "found /etc/hostname.$intf or /etc/hostname6.$intf, "\
+		    "ignoring ipadm configuration" > /dev/msglog
+		continue;
+	fi
+
+	# Enable the interface managed by ipadm
+	/sbin/ipadm enable-if -t $intf
+done
+
+#
 # Process the /etc/hostname[6].* files for IPMP interfaces.  Processing these
 # before non-IPMP interfaces avoids accidental implicit IPMP group creation.
 #
--- a/usr/src/cmd/svc/seed/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/svc/seed/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -67,7 +67,8 @@
 	../milestone/single-user.xml \
 	../milestone/usr-fs.xml \
 	../../dlmgmtd/dlmgmt.xml \
-	../../rpcbind/bind.xml \
+	../../cmd-inet/lib/ipmgmtd/network-ipmgmt.xml \
+	../../rpcbind/bind.xml
 
 #
 # Additional manifests for standalone Solaris
--- a/usr/src/cmd/truss/codes.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/cmd/truss/codes.c	Fri Mar 26 17:53:11 2010 -0400
@@ -879,6 +879,8 @@
 	{ (uint_t)SIOCSMSFILTER,	"SIOCSMSFILTER",    "group_filter" },
 	{ (uint_t)SIOCGIPMSFILTER,	"SIOCGIPMSFILTER",  "ip_msfilter" },
 	{ (uint_t)SIOCSIPMSFILTER,	"SIOCSIPMSFILTER",  "ip_msfilter" },
+	{ (uint_t)SIOCGLIFDADSTATE,	"SIOCGLIFDADSTATE",  "lifreq" },
+	{ (uint_t)SIOCSLIFPREFIX,	"SIOCSLIFPREFIX", "lifreq" },
 
 	/* DES encryption */
 	{ (uint_t)DESIOCBLOCK,	"DESIOCBLOCK", 	"desparams" },
--- a/usr/src/head/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/head/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # head/Makefile
@@ -79,6 +79,7 @@
 	grp.h		\
 	iconv.h		\
 	ieeefp.h	\
+	ifaddrs.h	\
 	inttypes.h	\
 	iso646.h	\
 	klpd.h		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/head/ifaddrs.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _IFADDRS_H
+#define	_IFADDRS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * The `getifaddrs' function generates a linked list of these structures.
+ * Each element of the list describes one network interface.
+ */
+#if defined(_INT64_TYPE)
+struct ifaddrs {
+	struct ifaddrs	*ifa_next;	/* Pointer to the next structure. */
+	char		*ifa_name;	/* Name of this network interface. */
+	uint64_t	ifa_flags;	/* Flags as from SIOCGLIFFLAGS ioctl. */
+	struct sockaddr_storage	*ifa_addr;
+					/* Network address of this interface. */
+	struct sockaddr_storage	*ifa_netmask;
+					/* Netmask of this interface. */
+	union {
+		/*
+		 * At most one of the following two is valid.  If the
+		 * IFF_BROADCAST bit is set in `ifa_flags', then
+		 * `ifa_broadaddr' is valid.  If the IFF_POINTOPOINT bit is
+		 * set, then `ifa_dstaddr' is valid. It is never the case that
+		 * both these bits are set at once.
+		 */
+		struct sockaddr_storage	*ifu_broadaddr;
+		struct sockaddr_storage	*ifu_dstaddr;
+	} ifa_ifu;
+	void		*ifa_data; /* Address-specific data (may be unused). */
+/*
+ * This may have been defined in <net/if.h>.
+ */
+#ifndef ifa_broadaddr
+#define	ifa_broadaddr	ifa_ifu.ifu_broadaddr	/* broadcast address */
+#endif
+#ifndef ifa_dstaddr
+#define	ifa_dstaddr	ifa_ifu.ifu_dstaddr	/* other end of p-to-p link */
+#endif
+};
+#endif
+
+/*
+ * Create a linked list of `struct ifaddrs' structures, one for each
+ * network interface on the host machine.  If successful, store the
+ * list in *ifap and return 0.  On errors, return -1 and set `errno'.
+ *
+ * The storage returned in *ifap is allocated dynamically and can
+ * only be properly freed by passing it to `freeifaddrs'.
+ */
+extern int getifaddrs(struct ifaddrs **);
+
+/* Reclaim the storage allocated by a previous `getifaddrs' call. */
+extern void freeifaddrs(struct ifaddrs *);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _IFADDRS_H */
--- a/usr/src/lib/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -112,6 +112,7 @@
 	libcryptoutil	\
 	libinetcfg	\
 	libinetutil	\
+	libipadm	\
 	libipmp		\
 	libiscsit	\
 	libkmf		\
@@ -334,6 +335,7 @@
 	libilb		\
 	libinetutil	\
 	libinstzones	\
+	libipadm	\
 	libnsl		\
 	libnwam		\
 	libpam		\
@@ -386,6 +388,7 @@
 	libc		\
 	libcmd		\
 	libcmdutils	\
+	libcommputil	\
 	libcontract	\
 	libcpc		\
 	libctf		\
@@ -411,8 +414,7 @@
 	libfru		\
 	libfstyp	\
 	libgen		\
-	libwanboot	\
-	libwanbootutil	\
+	libipadm	\
 	libipsecutil	\
 	libinetcfg	\
 	libinetsvc	\
@@ -445,7 +447,6 @@
 	librdc		\
 	libscf		\
 	libsip		\
-	libcommputil	\
 	libsmbios	\
 	librestart	\
 	librpcsvc	\
@@ -456,6 +457,7 @@
 	libshell	\
 	libslp		\
 	libsmedia	\
+	libsocket	\
 	libsqlite	\
 	libfcoe		\
 	libstmf		\
@@ -473,6 +475,8 @@
 	libumem		\
 	libunistat	\
 	libuutil	\
+	libwanboot	\
+	libwanbootutil	\
 	libwrap		\
 	libxcurses2	\
 	libzfs		\
@@ -592,7 +596,9 @@
 libfstyp:	libnvpair
 libelfsign:	libcryptoutil libkmf
 libidmap:	libadutils libldap5 libavl libsldap
-libinetcfg:	libnsl libsocket libdlpi
+libinetcfg:	libnsl libsocket libdlpi libinetutil
+libipadm:	libnsl libinetutil libsocket libdlpi libnvpair libdhcpagent \
+		libdladm libsecdb
 libiscsit:	libc libnvpair libstmf libuuid libnsl
 libkmf:		libcryptoutil pkcs11
 libnsl:		libmd5 libscf
--- a/usr/src/lib/brand/solaris10/zone/s10_boot.ksh	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/brand/solaris10/zone/s10_boot.ksh	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # s10 boot script.
@@ -144,6 +144,13 @@
 replace_with_native /sbin/ifconfig 0555 root:bin
 
 #
+# PSARC 2009/306 removed the ND_SET/ND_GET ioctl's for modifying
+# IP/TCP/UDP/SCTP/ICMP tunables. If S10 ndd(1M) is used within an
+# S10 container, the kernel will return EINVAL. So we need this.
+#
+replace_with_native /usr/sbin/ndd 0555 root:bin
+
+#
 # Replace automount and automountd with native wrappers.
 #
 if [ ! -h $ZONEROOT/usr/lib/fs/autofs -a -d $ZONEROOT/usr/lib/fs/autofs ]; then
--- a/usr/src/lib/libbc/inc/include/net/if.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libbc/inc/include/net/if.h	Fri Mar 26 17:53:11 2010 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 1990 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -12,8 +12,6 @@
 #ifndef _net_if_h
 #define	_net_if_h
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Structures defining a network interface, providing a packet
  * transport mechanism (ala level 0 of the PUP protocols).
@@ -94,7 +92,7 @@
 #define	IFF_NOARP	0x80		/* no address resolution protocol */
 #define	IFF_PROMISC	0x100		/* receive all packets */
 #define	IFF_ALLMULTI	0x200		/* receive all multicast packets */
-#define IFF_PRIVATE	0x8000		/* do not advertise */
+#define	IFF_PRIVATE	0x8000		/* do not advertise */
 
 /* flags set internally only: */
 #define	IFF_CANTCHANGE \
@@ -131,8 +129,8 @@
  * IF_ADJ should be used otherwise to adjust for its presence.
  */
 #define	IF_ADJ(m) { \
-	(m)->m_off += sizeof(struct ifnet *); \
-	(m)->m_len -= sizeof(struct ifnet *); \
+	(m)->m_off += sizeof (struct ifnet *); \
+	(m)->m_len -= sizeof (struct ifnet *); \
 	if ((m)->m_len == 0) { \
 		struct mbuf *n; \
 		MFREE((m), n); \
@@ -175,8 +173,12 @@
 		struct	sockaddr ifu_broadaddr;
 		struct	sockaddr ifu_dstaddr;
 	} ifa_ifu;
+#ifndef ifa_broadaddr
 #define	ifa_broadaddr	ifa_ifu.ifu_broadaddr	/* broadcast address */
+#endif
+#ifndef ifa_dstaddr
 #define	ifa_dstaddr	ifa_ifu.ifu_dstaddr	/* other end of p-to-p link */
+#endif
 	struct	ifnet *ifa_ifp;		/* back-pointer to interface */
 	struct	ifaddr *ifa_next;	/* next address for interface */
 };
@@ -223,7 +225,7 @@
 
 		struct ifr_fddi_gen_struct {
 			int	ifru_fddi_gioctl; /* field for gen ioctl */
-			caddr_t ifru_fddi_gaddr ; /* Generic ptr to a field */
+			caddr_t ifru_fddi_gaddr; /* Generic ptr to a field */
 		} ifru_fddi_gstruct;
 
 	} ifr_ifru;
@@ -237,10 +239,10 @@
 #define	ifr_data	ifr_ifru.ifru_data	/* for use by interface */
 
 /* FDDI specific */
-#define ifr_dnld_req	ifr_ifru.ifru_dnld_req
-#define ifr_fddi_stat	ifr_ifru.ifru_fddi_stat
-#define ifr_fddi_netmap	ifr_ifru.ifru_netmapent	/* FDDI network map entries */
-#define ifr_fddi_gstruct ifr_ifru.ifru_fddi_gstruct   
+#define	ifr_dnld_req	ifr_ifru.ifru_dnld_req
+#define	ifr_fddi_stat	ifr_ifru.ifru_fddi_stat
+#define	ifr_fddi_netmap	ifr_ifru.ifru_netmapent	/* FDDI network map entries */
+#define	ifr_fddi_gstruct ifr_ifru.ifru_fddi_gstruct
 
 };
 
--- a/usr/src/lib/libinetcfg/common/inetcfg.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libinetcfg/common/inetcfg.c	Fri Mar 26 17:53:11 2010 -0400
@@ -128,32 +128,6 @@
 }
 
 /*
- * Convert a prefix length to a netmask. Note that the mask array
- * should zero'ed by the caller.
- *
- * Returns: ICFG_SUCCESS or ICFG_FAILURE.
- */
-static int
-prefixlen_to_mask(int prefixlen, int maxlen, uchar_t *mask)
-{
-	if ((prefixlen < 0) || (prefixlen > maxlen)) {
-		errno = EINVAL;
-		return (ICFG_FAILURE);
-	}
-
-	while (prefixlen > 0) {
-		if (prefixlen >= 8) {
-			*mask++ = 0xFF;
-			prefixlen -= 8;
-			continue;
-		}
-		*mask |= 1 << (8 - prefixlen);
-		prefixlen--;
-	}
-	return (ICFG_SUCCESS);
-}
-
-/*
  * Copies an an IPv4 or IPv6 address from a sockaddr_storage
  * structure into the appropriate sockaddr structure for the
  * address family (sockaddr_in for AF_INET or sockaddr_in6 for
@@ -573,34 +547,16 @@
 {
 	struct lifreq lifr;
 
-	(void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
 	(void) strlcpy(lifr.lifr_name, icfg_if_name(handle),
 	    sizeof (lifr.lifr_name));
-	lifr.lifr_addr.ss_family = icfg_if_protocol(handle);
 
-	if (icfg_if_protocol(handle) == AF_INET6) {
-		struct sockaddr_in6 *sin6;
-		int ret;
-
-		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
-		if ((ret = prefixlen_to_mask(prefixlen, IPV6_ABITS,
-		    (uchar_t *)&sin6->sin6_addr)) != ICFG_SUCCESS) {
-			return (ret);
-		}
-	} else {
-		struct sockaddr_in *sin;
-		int ret;
-
-		sin = (struct sockaddr_in *)&lifr.lifr_addr;
-		if ((ret = prefixlen_to_mask(prefixlen, IP_ABITS,
-		    (uchar_t *)&sin->sin_addr)) != ICFG_SUCCESS) {
-			return (ret);
-		}
+	if (plen2mask(prefixlen, icfg_if_protocol(handle),
+	    &lifr.lifr_addr) != 0) {
+		return (ICFG_FAILURE);
 	}
 
-	if (ioctl(handle->ifh_sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
+	if (ioctl(handle->ifh_sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
 		return (ICFG_FAILURE);
-	}
 
 	return (ICFG_SUCCESS);
 }
--- a/usr/src/lib/libinetutil/common/inetutil.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libinetutil/common/inetutil.c	Fri Mar 26 17:53:11 2010 -0400
@@ -20,15 +20,17 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #include <unistd.h>
 #include <netinet/in.h>
 #include <libinetutil.h>
-
-extern int getnetmaskbyaddr(const struct in_addr, struct in_addr *);
+#include <inet/ip.h>
+#include <strings.h>
+#include <errno.h>
+#include <libsocket_priv.h>
 
 /*
  * Internet utility functions.
@@ -95,3 +97,97 @@
 	}
 	return (B_FALSE);
 }
+
+/*
+ * Stores the netmask in `mask' for the given prefixlen `plen' and also sets
+ * `ss_family' in `mask'.
+ */
+int
+plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr_storage *mask)
+{
+	uint8_t	*addr;
+
+	bzero(mask, sizeof (*mask));
+	mask->ss_family = af;
+	if (af == AF_INET) {
+		if (prefixlen > IP_ABITS)
+			return (EINVAL);
+		addr = (uint8_t *)&((struct sockaddr_in *)mask)->
+		    sin_addr.s_addr;
+	} else {
+		if (prefixlen > IPV6_ABITS)
+			return (EINVAL);
+		addr = (uint8_t *)&((struct sockaddr_in6 *)mask)->
+		    sin6_addr.s6_addr;
+	}
+
+	while (prefixlen > 0) {
+		if (prefixlen >= 8) {
+			*addr++ = 0xFF;
+			prefixlen -= 8;
+			continue;
+		}
+		*addr |= 1 << (8 - prefixlen);
+		prefixlen--;
+	}
+	return (0);
+}
+
+/*
+ * Convert a mask to a prefix length.
+ * Returns prefix length on success, -1 otherwise.
+ */
+int
+mask2plen(const struct sockaddr_storage *mask)
+{
+	int rc = 0;
+	uint8_t last;
+	uint8_t *addr;
+	int limit;
+
+	if (mask->ss_family == AF_INET) {
+		limit = IP_ABITS;
+		addr = (uint8_t *)&((struct sockaddr_in *)mask)->
+		    sin_addr.s_addr;
+	} else {
+		limit = IPV6_ABITS;
+		addr = (uint8_t *)&((struct sockaddr_in6 *)mask)->
+		    sin6_addr.s6_addr;
+	}
+
+	while (*addr == 0xff) {
+		rc += 8;
+		if (rc == limit)
+			return (limit);
+		addr++;
+	}
+
+	last = *addr;
+	while (last != 0) {
+		rc++;
+		last = (last << 1) & 0xff;
+	}
+
+	return (rc);
+}
+
+/*
+ * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or
+ * :: for IPv6. Otherwise, returns B_FALSE.
+ */
+boolean_t
+sockaddrunspec(const struct sockaddr_storage *ss)
+{
+	struct sockaddr_storage zeroaddr = {0};
+
+	switch (ss->ss_family) {
+	case AF_INET:
+		return (((struct sockaddr_in *)ss)->sin_addr.s_addr ==
+		    INADDR_ANY);
+	case AF_INET6:
+		return (IN6_IS_ADDR_UNSPECIFIED(
+		    &((struct sockaddr_in6 *)ss)->sin6_addr));
+	}
+
+	return (bcmp(&zeroaddr, ss, sizeof (zeroaddr)) == 0);
+}
--- a/usr/src/lib/libinetutil/common/libinetutil.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libinetutil/common/libinetutil.h	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,10 +50,14 @@
 	char		ifsp_devnm[LIFNAMSIZ];	/* only the device name */
 } ifspec_t;
 
-extern boolean_t ifparse_ifspec(const char *, ifspec_t *);
-extern void get_netmask4(const struct in_addr *, struct in_addr *);
-extern boolean_t sockaddrcmp(const struct sockaddr_storage *,
-    const struct sockaddr_storage *);
+extern boolean_t	ifparse_ifspec(const char *, ifspec_t *);
+extern void		get_netmask4(const struct in_addr *, struct in_addr *);
+extern boolean_t	sockaddrcmp(const struct sockaddr_storage *,
+			    const struct sockaddr_storage *);
+extern int		plen2mask(uint_t, sa_family_t,
+			    struct sockaddr_storage *);
+extern int		mask2plen(const struct sockaddr_storage *);
+extern boolean_t	sockaddrunspec(const struct sockaddr_storage *);
 
 /*
  * Extended version of the classic BSD ifaddrlist() interface:
--- a/usr/src/lib/libinetutil/common/mapfile-vers	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libinetutil/common/mapfile-vers	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -62,12 +62,15 @@
 	iu_tq_destroy;
 	iu_unregister_event;
 	octet_to_hexascii;
-	sockaddrcmp;
 	ofmt_open;
 	ofmt_close;
 	ofmt_print;
 	ofmt_update_winsize;
 	ofmt_strerror;
+	mask2plen;
+	plen2mask;
+	sockaddrcmp;
+	sockaddrunspec;
     local:
 	*;
 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include $(SRC)/lib/Makefile.lib
+
+HDRS =		libipadm.h ipadm_ndpd.h ipadm_ipmgmt.h
+HDRDIR =	common
+SUBDIRS =	$(MACH)
+POFILE =	libipadm.po
+MSGFILES =	common/libipadm.c common/ipadm_prop.c common/ipadm_persist.c \
+		common/ipadm_addr.c common/ipadm_if.c common/ipadm_ndpd.c
+XGETFLAGS =     -a -x libipadm.xcl
+
+all :=		TARGET = all
+clean :=	TARGET = clean
+clobber :=	TARGET = clobber
+install :=	TARGET = install
+lint :=		TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+install_h:	$(ROOTHDRS)
+
+check:		$(CHECKHDRS)
+
+$(POFILE):	pofile_MSGFILES
+
+_msg:		$(MSGDOMAINPOFILE)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+include $(SRC)/lib/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/Makefile.com	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+LIBRARY = libipadm.a
+VERS    = .1
+OBJECTS = libipadm.o ipadm_prop.o ipadm_persist.o ipadm_addr.o ipadm_if.o \
+	  ipadm_ndpd.o
+
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+LDLIBS +=	-lc -lnsl -linetutil -lsocket -ldlpi -lnvpair -ldhcpagent \
+	        -ldladm -lsecdb
+
+SRCDIR =	../common
+$(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS +=	$(CCVERBOSE)
+CPPFLAGS +=	-I$(SRCDIR) -D_REENTRANT
+
+.KEEP_STATE:
+
+all:		$(LIBS)
+
+lint:		lintcheck
+
+include $(SRC)/lib/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_addr.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,3466 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file contains functions for address management such as creating
+ * an address, deleting an address, enabling an address, disabling an
+ * address, bringing an address down or up, setting/getting properties
+ * on an address object and listing address information
+ * for all addresses in active as well as persistent configuration.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <inet/ip.h>
+#include <string.h>
+#include <strings.h>
+#include <assert.h>
+#include <sys/sockio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <zone.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <dhcpagent_util.h>
+#include <dhcpagent_ipc.h>
+#include <ipadm_ndpd.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <libdliptun.h>
+#include <ifaddrs.h>
+#include "libipadm_impl.h"
+
+#define	SIN6(a)		((struct sockaddr_in6 *)a)
+#define	SIN(a)		((struct sockaddr_in *)a)
+
+static ipadm_status_t	i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
+			    uint32_t);
+static ipadm_status_t	i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
+			    uint32_t);
+static ipadm_status_t	i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
+			    boolean_t);
+static ipadm_status_t	i_ipadm_get_db_addr(ipadm_handle_t, const char *,
+			    const char *, nvlist_t **);
+static ipadm_status_t	i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
+			    int *);
+static ipadm_status_t	i_ipadm_validate_create_addr(ipadm_handle_t,
+			    ipadm_addrobj_t, uint32_t);
+static ipadm_status_t	i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
+			    uint32_t);
+static ipadm_status_t	i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
+			    uint32_t *);
+static ipadm_status_t	i_ipadm_get_static_addr_db(ipadm_handle_t,
+			    ipadm_addrobj_t);
+static boolean_t	i_ipadm_is_user_aobjname_valid(const char *);
+
+/*
+ * Callback functions to retrieve property values from the kernel. These
+ * functions, when required, translate the values from the kernel to a format
+ * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
+ * for a given property.
+ */
+static ipadm_pd_getf_t	i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
+			i_ipadm_get_zone, i_ipadm_get_broadcast;
+
+/*
+ * Callback functions to set property values. These functions translate the
+ * values to a format suitable for kernel consumption, allocate the necessary
+ * ioctl buffers and then invoke ioctl().
+ */
+static ipadm_pd_setf_t	i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
+			i_ipadm_set_zone;
+
+/* address properties description table */
+ipadm_prop_desc_t ipadm_addrprop_table[] = {
+	{ "broadcast", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    NULL, NULL, i_ipadm_get_broadcast },
+
+	{ "deprecated", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    i_ipadm_set_addr_flag, i_ipadm_get_onoff,
+	    i_ipadm_get_addr_flag },
+
+	{ "prefixlen", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
+	    i_ipadm_get_prefixlen },
+
+	{ "private", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
+
+	{ "transmit", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
+
+	{ "zone", IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE,
+	    i_ipadm_set_zone, NULL, i_ipadm_get_zone },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+static ipadm_prop_desc_t up_addrprop = { "up", IPADMPROP_CLASS_ADDR,
+					MOD_PROTO_NONE, NULL, NULL, NULL };
+
+/*
+ * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
+ * `ipadm_atype' fields of the given `ipaddr'.
+ */
+void
+i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
+    const char *aobjname, ipadm_addr_type_t atype)
+{
+	bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
+	(void) strlcpy(ipaddr->ipadm_ifname, ifname,
+	    sizeof (ipaddr->ipadm_ifname));
+	(void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
+	    sizeof (ipaddr->ipadm_aobjname));
+	ipaddr->ipadm_atype = atype;
+}
+
+/*
+ * Determine the permission of the property depending on whether it has a
+ * set() and/or get() callback functions.
+ */
+static ipadm_status_t
+i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
+{
+	uint_t	perm;
+	size_t	nbytes;
+
+	perm = 0;
+	if (pdp->ipd_set != NULL)
+		perm |= MOD_PROP_PERM_WRITE;
+	if (pdp->ipd_get != NULL)
+		perm |= MOD_PROP_PERM_READ;
+
+	nbytes = snprintf(buf, *bufsize, "%c%c",
+	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
+	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
+
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
+ * retrieves the information necessary for any operation on the object,
+ * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
+ * refresh-addr, get-addrprop or set-addrprop. The information include
+ * the logical interface number, address type, address family,
+ * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
+ * the ipadm_flags that indicate if the address is present in
+ * active configuration or persistent configuration or both. If the address
+ * is not found, IPADM_NOTSUP is returned.
+ */
+ipadm_status_t
+i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
+{
+	ipmgmt_aobjop_arg_t	larg;
+	ipmgmt_aobjop_rval_t	rval, *rvalp;
+	int			err = 0;
+
+	/* populate the door_call argument structure */
+	larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
+	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
+	    sizeof (larg.ia_aobjname));
+
+	rvalp = &rval;
+	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
+	    sizeof (rval), B_FALSE);
+	if (err != 0)
+		return (ipadm_errno2status(err));
+	(void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
+	    sizeof (ipaddr->ipadm_ifname));
+	ipaddr->ipadm_lifnum = rval.ir_lnum;
+	ipaddr->ipadm_atype = rval.ir_atype;
+	ipaddr->ipadm_af = rval.ir_family;
+	ipaddr->ipadm_flags = rval.ir_flags;
+	if (rval.ir_atype == IPADM_ADDR_IPV6_ADDRCONF) {
+		(void) memcpy(&ipaddr->ipadm_intfid, &rval.ir_ifid,
+		    sizeof (ipaddr->ipadm_intfid));
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Retrieves the static address (IPv4 or IPv6) for the given address object
+ * in `ipaddr' from persistent DB.
+ */
+static ipadm_status_t
+i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
+{
+	ipadm_status_t		status;
+	nvlist_t		*onvl;
+	nvlist_t		*anvl = NULL;
+	nvlist_t		*nvladdr;
+	nvpair_t		*nvp;
+	char			*name;
+	char			*aobjname = ipaddr->ipadm_aobjname;
+	char			*sname;
+	sa_family_t		af = AF_UNSPEC;
+
+	/*
+	 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
+	 */
+	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	/*
+	 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
+	 * or the IPADM_NVP_IPV6ADDR name-value pair.
+	 */
+	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(onvl, NULL)) {
+		if (nvpair_value_nvlist(nvp, &anvl) != 0)
+			continue;
+		if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
+		    nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
+			break;
+	}
+	if (nvp == NULL)
+		goto fail;
+	for (nvp = nvlist_next_nvpair(anvl, NULL);
+	    nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
+			af = AF_INET;
+			break;
+		} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
+			af = AF_INET6;
+			break;
+		}
+	}
+	assert(af != AF_UNSPEC);
+	if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
+	    nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
+	    ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
+		goto fail;
+	}
+	nvlist_free(onvl);
+	return (IPADM_SUCCESS);
+fail:
+	nvlist_free(onvl);
+	return (IPADM_NOTFOUND);
+}
+
+/*
+ * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
+ * fills in the address objname, the address type and the ipadm_flags.
+ */
+ipadm_status_t
+i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
+{
+	ipmgmt_aobjop_arg_t	larg;
+	ipmgmt_aobjop_rval_t	rval, *rvalp;
+	int			err;
+
+	larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
+	(void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
+	    sizeof (larg.ia_ifname));
+	larg.ia_lnum = addrobj->ipadm_lifnum;
+	larg.ia_family = addrobj->ipadm_af;
+
+	rvalp = &rval;
+	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
+	    sizeof (rval), B_FALSE);
+	if (err != 0)
+		return (ipadm_errno2status(err));
+	(void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
+	    sizeof (addrobj->ipadm_aobjname));
+	addrobj->ipadm_atype = rval.ir_atype;
+	addrobj->ipadm_flags = rval.ir_flags;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
+ * with the given name and logical interface number.
+ * This API is called by in.ndpd to add addrobjs when new prefixes or
+ * dhcpv6 addresses are configured.
+ */
+ipadm_status_t
+ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    const char *aobjname, ipadm_addr_type_t atype, int lnum)
+{
+	ipmgmt_aobjop_arg_t	larg;
+	int			err;
+
+	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
+	(void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
+	(void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
+	larg.ia_atype = atype;
+	larg.ia_lnum = lnum;
+	larg.ia_family = af;
+	err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Deletes an address object with given name and logical number from ipmgmtd
+ * daemon's aobjmap (active configuration). This API is called by in.ndpd to
+ * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
+ * removed.
+ */
+ipadm_status_t
+ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    const char *aobjname, ipadm_addr_type_t atype, int lnum)
+{
+	struct ipadm_addrobj_s	aobj;
+
+	i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
+	aobj.ipadm_af = af;
+	aobj.ipadm_lifnum = lnum;
+	return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
+}
+
+/*
+ * Gets all the addresses from active configuration and populates the
+ * address information in `addrinfo'.
+ */
+static ipadm_status_t
+i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
+{
+	ipadm_status_t		status;
+	struct ifaddrs		*ifap, *ifa;
+	ipadm_addr_info_t	*curr, *prev = NULL;
+	struct ifaddrs		*cifaddr;
+	struct lifreq		lifr;
+	int			sock;
+	uint64_t		flags;
+	char			cifname[LIFNAMSIZ];
+	struct sockaddr_in6	*sin6;
+	struct ipadm_addrobj_s	ipaddr;
+	char			*sep;
+	int			lnum;
+
+retry:
+	*addrinfo = NULL;
+
+	/* Get all the configured addresses */
+	if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
+		return (ipadm_errno2status(errno));
+	/* Return if there is nothing to process. */
+	if (ifa == NULL)
+		return (IPADM_SUCCESS);
+	bzero(&lifr, sizeof (lifr));
+	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
+		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
+		lnum = 0;
+		if ((sep = strrchr(cifname, ':')) != NULL) {
+			*sep++ = '\0';
+			lnum = atoi(sep);
+		}
+		if (ifname != NULL && strcmp(cifname, ifname) != 0)
+			continue;
+		if (!(ipadm_flags & IPADM_OPT_ZEROADDR)) {
+			/*
+			 * Do not list it if it is zero, unless
+			 * it is under DHCP or has a non-zero
+			 * destination address.
+			 */
+			if (sockaddrunspec(ifap->ifa_addr) &&
+			    (!(ifap->ifa_flags & IFF_DHCPRUNNING) &&
+			    (!(ifap->ifa_flags & IFF_POINTOPOINT) ||
+			    sockaddrunspec(ifap->ifa_dstaddr)))) {
+				continue;
+			}
+		}
+
+		/* Allocate and populate the current node in the list. */
+		if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
+			goto fail;
+
+		/* Link to the list in `addrinfo'. */
+		if (prev != NULL)
+			prev->ia_ifa.ifa_next = &curr->ia_ifa;
+		else
+			*addrinfo = curr;
+		prev = curr;
+
+		cifaddr = &curr->ia_ifa;
+		if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
+			goto fail;
+		cifaddr->ifa_flags = ifap->ifa_flags;
+		cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
+		if (cifaddr->ifa_addr == NULL)
+			goto fail;
+		*cifaddr->ifa_addr = *ifap->ifa_addr;
+		cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
+		if (cifaddr->ifa_netmask == NULL)
+			goto fail;
+		*cifaddr->ifa_netmask = *ifap->ifa_netmask;
+		if (ifap->ifa_flags & IFF_POINTOPOINT) {
+			cifaddr->ifa_dstaddr = malloc(
+			    sizeof (struct sockaddr_storage));
+			if (cifaddr->ifa_dstaddr == NULL)
+				goto fail;
+			*cifaddr->ifa_dstaddr = *ifap->ifa_dstaddr;
+		} else if (ifap->ifa_flags & IFF_BROADCAST) {
+			cifaddr->ifa_broadaddr = malloc(
+			    sizeof (struct sockaddr_storage));
+			if (cifaddr->ifa_broadaddr == NULL)
+				goto fail;
+			*cifaddr->ifa_broadaddr = *ifap->ifa_broadaddr;
+		}
+		/* Get the addrobj name stored for this logical interface. */
+		ipaddr.ipadm_aobjname[0] = '\0';
+		(void) strlcpy(ipaddr.ipadm_ifname, cifname,
+		    sizeof (ipaddr.ipadm_ifname));
+		ipaddr.ipadm_lifnum = lnum;
+		ipaddr.ipadm_af = ifap->ifa_addr->ss_family;
+		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
+
+		/*
+		 * Find address type from ifa_flags, if we could not get it
+		 * from daemon.
+		 */
+		sin6 = SIN6(ifap->ifa_addr);
+		flags = ifap->ifa_flags;
+		if (status == IPADM_SUCCESS) {
+			(void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
+			    sizeof (curr->ia_aobjname));
+			curr->ia_atype = ipaddr.ipadm_atype;
+		} else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
+		    !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
+			curr->ia_atype = IPADM_ADDR_DHCP;
+		} else if (flags & IFF_ADDRCONF) {
+			curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
+		} else {
+			curr->ia_atype = IPADM_ADDR_STATIC;
+		}
+		/*
+		 * Populate the flags for the active configuration from the
+		 * `ifa_flags'.
+		 */
+		if (!(flags & IFF_UP)) {
+			if (flags & IFF_DUPLICATE)
+				curr->ia_state = IFA_DUPLICATE;
+			else
+				curr->ia_state = IFA_DOWN;
+		} else {
+			curr->ia_cflags |= IA_UP;
+			if (flags & IFF_RUNNING) {
+				(void) strlcpy(lifr.lifr_name, ifap->ifa_name,
+				    sizeof (lifr.lifr_name));
+				sock = (ifap->ifa_addr->ss_family == AF_INET) ?
+				    iph->iph_sock : iph->iph_sock6;
+				if (ioctl(sock, SIOCGLIFDADSTATE,
+				    (caddr_t)&lifr) < 0) {
+					if (errno == ENXIO) {
+						freeifaddrs(ifa);
+						ipadm_free_addr_info(*addrinfo);
+						goto retry;
+					}
+					goto fail;
+				}
+				if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
+					curr->ia_state = IFA_TENTATIVE;
+				else
+					curr->ia_state = IFA_OK;
+			} else {
+				curr->ia_state = IFA_INACCESSIBLE;
+			}
+		}
+		if (flags & IFF_UNNUMBERED)
+			curr->ia_cflags |= IA_UNNUMBERED;
+		if (flags & IFF_PRIVATE)
+			curr->ia_cflags |= IA_PRIVATE;
+		if (flags & IFF_TEMPORARY)
+			curr->ia_cflags |= IA_TEMPORARY;
+		if (flags & IFF_DEPRECATED)
+			curr->ia_cflags |= IA_DEPRECATED;
+
+	}
+
+	freeifaddrs(ifa);
+	return (IPADM_SUCCESS);
+
+fail:
+	/* On error, cleanup everything and return. */
+	ipadm_free_addr_info(*addrinfo);
+	*addrinfo = NULL;
+	freeifaddrs(ifa);
+	return (ipadm_errno2status(errno));
+}
+
+/*
+ * From the given `name', i_ipadm_name2atype() deduces the address type
+ * and address family. If the `name' implies an address, it returns B_TRUE.
+ * Else, returns B_FALSE and leaves the output parameters unchanged.
+ */
+boolean_t
+i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
+{
+	boolean_t	is_addr = B_TRUE;
+
+	if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
+		*af = AF_INET;
+		*type = IPADM_ADDR_STATIC;
+	} else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
+		*af = AF_INET6;
+		*type = IPADM_ADDR_STATIC;
+	} else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
+		*af = AF_INET;
+		*type = IPADM_ADDR_DHCP;
+	} else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
+		*af = AF_INET6;
+		*type = IPADM_ADDR_IPV6_ADDRCONF;
+	} else {
+		is_addr = B_FALSE;
+	}
+
+	return (is_addr);
+}
+
+/*
+ * Parses the given nvlist `nvl' for an address or an address property.
+ * The input nvlist must contain either an address or an address property.
+ * `ainfo' is an input as well as output parameter. When an address or an
+ * address property is found, `ainfo' is updated with the information found.
+ * Some of the fields may be already filled in by the calling function.
+ *
+ * The fields that will be filled/updated by this function are `ia_pflags',
+ * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
+ * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
+ * obtained if `nvl' contains an address.
+ */
+static ipadm_status_t
+i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
+{
+	nvlist_t		*nvladdr;
+	char			*name;
+	char			*propstr = NULL;
+	char			*sname, *dname;
+	nvpair_t		*nvp;
+	sa_family_t		af;
+	ipadm_addr_type_t	atype;
+	boolean_t		is_addr = B_FALSE;
+	int			err;
+
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (i_ipadm_name2atype(name, &af, &atype)) {
+			err = nvpair_value_nvlist(nvp, &nvladdr);
+			is_addr = B_TRUE;
+		} else if (IPADM_PRIV_NVP(name)) {
+			continue;
+		} else {
+			err = nvpair_value_string(nvp, &propstr);
+		}
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+
+	if (is_addr) {
+		/*
+		 * We got an address from the nvlist `nvl'.
+		 * Parse `nvladdr' and populate relevant information
+		 * in `ainfo'.
+		 */
+		switch (atype) {
+		case IPADM_ADDR_STATIC:
+			if (strcmp(name, "up") == 0 &&
+			    strcmp(propstr, "yes") == 0) {
+				ainfo->ia_pflags |= IA_UP;
+			}
+			/*
+			 * For static addresses, we need to get the hostnames.
+			 */
+			err = nvlist_lookup_string(nvladdr,
+			    IPADM_NVP_IPADDRHNAME, &sname);
+			if (err != 0)
+				return (ipadm_errno2status(err));
+			(void) strlcpy(ainfo->ia_sname, sname,
+			    sizeof (ainfo->ia_sname));
+			err = nvlist_lookup_string(nvladdr,
+			    IPADM_NVP_IPDADDRHNAME, &dname);
+			if (err == 0) {
+				(void) strlcpy(ainfo->ia_dname, dname,
+				    sizeof (ainfo->ia_dname));
+			}
+			break;
+		case IPADM_ADDR_DHCP:
+		case IPADM_ADDR_IPV6_ADDRCONF:
+			/*
+			 * dhcp and addrconf address objects are always
+			 * marked up when re-enabled.
+			 */
+			ainfo->ia_pflags |= IA_UP;
+			break;
+		default:
+			return (IPADM_FAILURE);
+		}
+	} else {
+		/*
+		 * We got an address property from `nvl'. Parse the
+		 * name and the property value. Update the `ainfo->ia_pflags'
+		 * for the flags.
+		 */
+		if (strcmp(name, "deprecated") == 0) {
+			if (strcmp(propstr, IPADM_ONSTR) == 0)
+				ainfo->ia_pflags |= IA_DEPRECATED;
+		} else if (strcmp(name, "private") == 0) {
+			if (strcmp(propstr, IPADM_ONSTR) == 0)
+				ainfo->ia_pflags |= IA_PRIVATE;
+		}
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Parses the given nvlist `nvl' for an address or an address property.
+ * The input nvlist must contain either an address or an address property.
+ * `ainfo' is an input as well as output parameter. When an address or an
+ * address property is found, `ainfo' is updated with the information found.
+ * Some of the fields may be already filled in by the calling function,
+ * because of previous calls to i_ipadm_nvl2ainfo_active().
+ *
+ * Since the address object in `nvl' is also in the active configuration, the
+ * fields that will be filled/updated by this function are `ia_pflags',
+ * `ia_sname' and `ia_dname'.
+ *
+ * If this function returns an error, the calling function will take
+ * care of freeing the fields in `ainfo'.
+ */
+static ipadm_status_t
+i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
+{
+	return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
+}
+
+/*
+ * Parses the given nvlist `nvl' for an address or an address property.
+ * The input nvlist must contain either an address or an address property.
+ * `ainfo' is an input as well as output parameter. When an address or an
+ * address property is found, `ainfo' is updated with the information found.
+ * Some of the fields may be already filled in by the calling function,
+ * because of previous calls to i_ipadm_nvl2ainfo_persist().
+ *
+ * All the relevant fields in `ainfo' will be filled by this function based
+ * on what we find in `nvl'.
+ *
+ * If this function returns an error, the calling function will take
+ * care of freeing the fields in `ainfo'.
+ */
+static ipadm_status_t
+i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
+{
+	nvlist_t		*nvladdr;
+	struct ifaddrs		*ifa;
+	char			*name;
+	char			*ifname = NULL;
+	char			*aobjname = NULL;
+	char			*propstr = NULL;
+	nvpair_t		*nvp;
+	sa_family_t		af;
+	ipadm_addr_type_t	atype;
+	boolean_t		is_addr = B_FALSE;
+	size_t			size = sizeof (struct sockaddr_storage);
+	struct sockaddr_in6	*sin6;
+	uint32_t		plen = 0;
+	int			err;
+	ipadm_status_t		status;
+
+	status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
+			err = nvpair_value_string(nvp, &ifname);
+		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
+			err = nvpair_value_string(nvp, &aobjname);
+		} else if (i_ipadm_name2atype(name, &af, &atype)) {
+			err = nvpair_value_nvlist(nvp, &nvladdr);
+			is_addr = B_TRUE;
+		} else {
+			err = nvpair_value_string(nvp, &propstr);
+		}
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+
+	ifa = &ainfo->ia_ifa;
+	(void) strlcpy(ainfo->ia_aobjname, aobjname,
+	    sizeof (ainfo->ia_aobjname));
+	if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
+		return (IPADM_NO_MEMORY);
+	if (is_addr) {
+		/*
+		 * We got an address from the nvlist `nvl'.
+		 * Parse `nvladdr' and populate `ifa->ifa_addr'.
+		 */
+		ainfo->ia_atype = atype;
+		if ((ifa->ifa_addr = calloc(1, size)) == NULL)
+			return (IPADM_NO_MEMORY);
+		switch (atype) {
+		case IPADM_ADDR_STATIC:
+			ifa->ifa_addr->ss_family = af;
+			break;
+		case IPADM_ADDR_DHCP:
+			ifa->ifa_addr->ss_family = AF_INET;
+			break;
+		case IPADM_ADDR_IPV6_ADDRCONF:
+			sin6 = SIN6(ifa->ifa_addr);
+			sin6->sin6_family = AF_INET6;
+			if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
+			    &sin6->sin6_addr) != IPADM_SUCCESS)
+				return (IPADM_NO_MEMORY);
+			err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
+			    &plen);
+			if (err != 0)
+				return (ipadm_errno2status(err));
+			if ((ifa->ifa_netmask = malloc(size)) == NULL)
+				return (IPADM_NO_MEMORY);
+			if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
+				return (ipadm_errno2status(err));
+			break;
+		default:
+			return (IPADM_FAILURE);
+		}
+	} else {
+		if (strcmp(name, "prefixlen") == 0) {
+			/*
+			 * If a prefixlen was found, update the
+			 * `ainfo->ia_ifa.ifa_netmask'.
+			 */
+
+			if ((ifa->ifa_netmask = malloc(size)) == NULL)
+				return (IPADM_NO_MEMORY);
+			/*
+			 * Address property lines always follow the address
+			 * line itself in the persistent db. We must have
+			 * found a valid `ainfo->ia_ifa.ifa_addr' by now.
+			 */
+			assert(ifa->ifa_addr != NULL);
+			err = plen2mask(atoi(propstr), ifa->ifa_addr->ss_family,
+			    ifa->ifa_netmask);
+			if (err != 0)
+				return (ipadm_errno2status(err));
+		}
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Retrieves all addresses from active config and appends to it the
+ * addresses that are found only in persistent config. In addition,
+ * it updates the persistent fields for each address from information
+ * found in persistent config. The output parameter `addrinfo' contains
+ * complete information regarding all addresses in active as well as
+ * persistent config.
+ */
+static ipadm_status_t
+i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
+{
+	nvlist_t		*nvladdr = NULL;
+	nvlist_t		*onvl = NULL;
+	nvpair_t		*nvp;
+	ipadm_status_t		status;
+	ipadm_addr_info_t	*ainfo = NULL;
+	ipadm_addr_info_t	*curr;
+	ipadm_addr_info_t	*last = NULL;
+	char			*aobjname;
+
+	/* Get all addresses from active config. */
+	status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
+	    lifc_flags);
+	if (status != IPADM_SUCCESS)
+		goto fail;
+
+	/* Get all addresses from persistent config. */
+	status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
+	/*
+	 * If no address was found in persistent config, just
+	 * return what we found in active config.
+	 */
+	if (status == IPADM_NOTFOUND) {
+		/*
+		 * If nothing was found neither active nor persistent
+		 * config, this means that the interface does not exist,
+		 * if one was provided in `ifname'.
+		 */
+		if (ainfo == NULL && ifname != NULL)
+			return (IPADM_ENXIO);
+		*addrinfo = ainfo;
+		return (IPADM_SUCCESS);
+	}
+	/* In case of any other error, cleanup and return. */
+	if (status != IPADM_SUCCESS)
+		goto fail;
+	/* we append to make sure, loopback addresses are first */
+	if (ainfo != NULL) {
+		for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
+			;
+		last = curr;
+	}
+
+	/*
+	 * `onvl' will contain all the address lines from the db. Each line
+	 * could contain the address itself or an address property. Addresses
+	 * and address properties are found in separate lines.
+	 *
+	 * If an address A was found in active, we will already have `ainfo',
+	 * and it is present in persistent configuration as well, we need to
+	 * update `ainfo' with persistent information (`ia_pflags).
+	 * For each address B found only in persistent configuration,
+	 * append the address to the list with the address info for B from
+	 * `onvl'.
+	 */
+	for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(onvl, nvp)) {
+		if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
+			continue;
+		if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
+		    &aobjname) != 0)
+			continue;
+		for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
+			if (strcmp(curr->ia_aobjname, aobjname) == 0)
+				break;
+		}
+		if (curr == NULL) {
+			/*
+			 * We did not find this address object in `ainfo'.
+			 * This means that the address object exists only
+			 * in the persistent configuration. Get its
+			 * details and append to `ainfo'.
+			 */
+			curr = calloc(1, sizeof (ipadm_addr_info_t));
+			if (curr == NULL)
+				goto fail;
+			curr->ia_state = IFA_DISABLED;
+			if (last != NULL)
+				last->ia_ifa.ifa_next = &curr->ia_ifa;
+			else
+				ainfo = curr;
+			last = curr;
+		}
+		/*
+		 * Fill relevant fields of `curr' from the persistent info
+		 * in `nvladdr'. Call the appropriate function based on the
+		 * `ia_state' value.
+		 */
+		if (curr->ia_state == IFA_DISABLED)
+			status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
+		else
+			status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
+		if (status != IPADM_SUCCESS)
+			goto fail;
+	}
+	*addrinfo = ainfo;
+	nvlist_free(onvl);
+	return (status);
+fail:
+	/* On error, cleanup and return. */
+	nvlist_free(onvl);
+	ipadm_free_addr_info(ainfo);
+	*addrinfo = NULL;
+	return (status);
+}
+
+/*
+ * Callback function that sets the property `prefixlen' on the address
+ * object in `arg' to the value in `pval'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
+{
+	struct sockaddr_storage	netmask;
+	struct lifreq		lifr;
+	int			err, s;
+	unsigned long		prefixlen, abits;
+	char			*end;
+	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
+
+	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
+		return (IPADM_NOTSUP);
+
+	errno = 0;
+	prefixlen = strtoul(pval, &end, 10);
+	if (errno != 0 || *end != '\0')
+		return (IPADM_INVALID_ARG);
+
+	abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
+	if (prefixlen == 0 || prefixlen == (abits - 1))
+		return (IPADM_INVALID_ARG);
+
+	if ((err = plen2mask(prefixlen, af, &netmask)) != 0)
+		return (ipadm_errno2status(err));
+
+	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+
+	bzero(&lifr, sizeof (lifr));
+	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
+	    sizeof (lifr.lifr_name));
+	(void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
+	if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+
+	/* now, change the broadcast address to reflect the prefixlen */
+	if (af == AF_INET) {
+		/*
+		 * get the interface address and set it, this should reset
+		 * the broadcast address.
+		 */
+		(void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
+		(void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+
+/*
+ * Callback function that sets the given value `pval' to one of the
+ * properties among `deprecated', `private', and `transmit' as defined in
+ * `pdp', on the address object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
+{
+	char		lifname[LIFNAMSIZ];
+	uint64_t	on_flags = 0, off_flags = 0;
+	boolean_t	on;
+	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
+
+	if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
+	    strcmp(pdp->ipd_name, "deprecated") == 0)
+		return (IPADM_NOTSUP);
+
+	if (strcmp(pval, IPADM_ONSTR) == 0)
+		on = B_TRUE;
+	else if (strcmp(pval, IPADM_OFFSTR) == 0)
+		on = B_FALSE;
+	else
+		return (IPADM_INVALID_ARG);
+
+	if (strcmp(pdp->ipd_name, "private") == 0) {
+		if (on)
+			on_flags = IFF_PRIVATE;
+		else
+			off_flags = IFF_PRIVATE;
+	} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
+		if (on)
+			off_flags = IFF_NOXMIT;
+		else
+			on_flags = IFF_NOXMIT;
+	} else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
+		if (on)
+			on_flags = IFF_DEPRECATED;
+		else
+			off_flags = IFF_DEPRECATED;
+	} else {
+		return (IPADM_PROP_UNKNOWN);
+	}
+
+	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+	return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
+}
+
+/*
+ * Callback function that sets the property `zone' on the address
+ * object in `arg' to the value in `pval'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
+{
+	struct lifreq	lifr;
+	zoneid_t	zoneid;
+	int		s;
+
+	/*
+	 * To modify the zone assignment such that it persists across
+	 * reboots, zonecfg(1M) must be used.
+	 */
+	if (flags & IPADM_OPT_PERSIST) {
+		return (IPADM_NOTSUP);
+	} else if (flags & IPADM_OPT_ACTIVE) {
+		/* put logical interface into all zones */
+		if (strcmp(pval, "all-zones") == 0) {
+			zoneid = ALL_ZONES;
+		} else {
+			/* zone must be ready or running */
+			if ((zoneid = getzoneidbyname(pval)) == -1)
+				return (ipadm_errno2status(errno));
+		}
+	} else {
+		return (IPADM_INVALID_ARG);
+	}
+
+	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+	bzero(&lifr, sizeof (lifr));
+	i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
+	    sizeof (lifr.lifr_name));
+	lifr.lifr_zoneid = zoneid;
+	if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Callback function that gets the property `broadcast' for the address
+ * object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	struct sockaddr_in	*sin;
+	struct lifreq		lifr;
+	char			lifname[LIFNAMSIZ];
+	ipadm_addrobj_t		ipaddr = (ipadm_addrobj_t)arg;
+	ipadm_status_t		status;
+	size_t			nbytes = 0;
+	uint64_t		ifflags = 0;
+
+	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
+		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		if (!(ifflags & IFF_BROADCAST)) {
+			buf[0] = '\0';
+			return (IPADM_SUCCESS);
+		}
+	}
+
+	switch (valtype) {
+	case MOD_PROP_DEFAULT: {
+		struct sockaddr_storage	mask;
+		struct in_addr		broadaddr;
+		uint_t			plen;
+		in_addr_t		addr, maddr;
+		char			val[MAXPROPVALLEN];
+		uint_t			valsz = MAXPROPVALLEN;
+		ipadm_status_t		status;
+		int			err;
+		struct sockaddr_in	*sin;
+
+		if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
+			/*
+			 * Since the address is unknown we cannot
+			 * obtain default prefixlen
+			 */
+			if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
+			    ipaddr->ipadm_af == AF_INET6) {
+				buf[0] = '\0';
+				return (IPADM_SUCCESS);
+			}
+			/*
+			 * For the static address, we get the address from the
+			 * persistent db.
+			 */
+			status = i_ipadm_get_static_addr_db(iph, ipaddr);
+			if (status != IPADM_SUCCESS)
+				return (status);
+			sin = SIN(&ipaddr->ipadm_static_addr);
+			addr = sin->sin_addr.s_addr;
+		} else {
+			/*
+			 * If the address object is active, we retrieve the
+			 * address from kernel.
+			 */
+			bzero(&lifr, sizeof (lifr));
+			(void) strlcpy(lifr.lifr_name, lifname,
+			    sizeof (lifr.lifr_name));
+			if (ioctl(iph->iph_sock, SIOCGLIFADDR,
+			    (caddr_t)&lifr) < 0)
+				return (ipadm_errno2status(errno));
+
+			addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
+		}
+		/*
+		 * For default broadcast address, get the address and the
+		 * default prefixlen for that address and then compute the
+		 * broadcast address.
+		 */
+		status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
+		    MOD_PROP_DEFAULT);
+		if (status != IPADM_SUCCESS)
+			return (status);
+
+		plen = atoi(val);
+		if ((err = plen2mask(plen, AF_INET, &mask)) != 0)
+			return (ipadm_errno2status(err));
+		maddr = (SIN(&mask))->sin_addr.s_addr;
+		broadaddr.s_addr = (addr & maddr) | ~maddr;
+		nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
+		break;
+	}
+	case MOD_PROP_ACTIVE:
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, lifname,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
+		    (caddr_t)&lifr) < 0) {
+			return (ipadm_errno2status(errno));
+		} else {
+			sin = SIN(&lifr.lifr_addr);
+			nbytes = snprintf(buf, *bufsize, "%s",
+			    inet_ntoa(sin->sin_addr));
+		}
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	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 `prefixlen'
+ * for the address object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	struct lifreq	lifr;
+	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
+	char		lifname[LIFNAMSIZ];
+	int		s;
+	uint32_t	prefixlen;
+	size_t		nbytes;
+	ipadm_status_t	status;
+	uint64_t	lifflags;
+
+	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+	if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
+		status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
+		if (status != IPADM_SUCCESS) {
+			return (status);
+		} else if (lifflags & IFF_POINTOPOINT) {
+			buf[0] = '\0';
+			return (status);
+		}
+	}
+
+	s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
+	switch (valtype) {
+	case MOD_PROP_POSSIBLE:
+		if (af == AF_INET)
+			nbytes = snprintf(buf, *bufsize, "1-30,32");
+		else
+			nbytes = snprintf(buf, *bufsize, "1-126,128");
+		break;
+	case MOD_PROP_DEFAULT:
+		if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
+			/*
+			 * For static addresses, we retrieve the address
+			 * from kernel if it is active.
+			 */
+			if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
+				return (ipadm_errno2status(errno));
+			status = i_ipadm_get_default_prefixlen(
+			    &lifr.lifr_addr, &prefixlen);
+			if (status != IPADM_SUCCESS)
+				return (status);
+		} else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
+		    ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
+			/*
+			 * Since the address is unknown we cannot
+			 * obtain default prefixlen
+			 */
+			buf[0] = '\0';
+			return (IPADM_SUCCESS);
+		} else {
+			/*
+			 * If not in active config, we use the address
+			 * from persistent store.
+			 */
+			status = i_ipadm_get_static_addr_db(iph, ipaddr);
+			if (status != IPADM_SUCCESS)
+				return (status);
+			status = i_ipadm_get_default_prefixlen(
+			    &ipaddr->ipadm_static_addr, &prefixlen);
+			if (status != IPADM_SUCCESS)
+				return (status);
+		}
+		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
+		break;
+	case MOD_PROP_ACTIVE:
+		if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		prefixlen = lifr.lifr_addrlen;
+		nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Callback function that retrieves the value of one of the properties
+ * among `deprecated', `private', and `transmit' for the address object
+ * in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	boolean_t	on = B_FALSE;
+	char		lifname[LIFNAMSIZ];
+	ipadm_status_t	status = IPADM_SUCCESS;
+	uint64_t	ifflags;
+	size_t		nbytes;
+	ipadm_addrobj_t	ipaddr = (ipadm_addrobj_t)arg;
+
+	switch (valtype) {
+	case MOD_PROP_DEFAULT:
+		if (strcmp(pdp->ipd_name, "private") == 0 ||
+		    strcmp(pdp->ipd_name, "deprecated") == 0) {
+			on = B_FALSE;
+		} else if (strcmp(pdp->ipd_name, "transmit") == 0) {
+			on = B_TRUE;
+		} else {
+			return (IPADM_PROP_UNKNOWN);
+		}
+		break;
+	case MOD_PROP_ACTIVE:
+		/*
+		 * If the address is present in active configuration, we
+		 * retrieve it from kernel to get the property value.
+		 * Else, there is no value to return.
+		 */
+		i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+		status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		if (strcmp(pdp->ipd_name, "private") == 0)
+			on = (ifflags & IFF_PRIVATE);
+		else if (strcmp(pdp->ipd_name, "transmit") == 0)
+			on = !(ifflags & IFF_NOXMIT);
+		else if (strcmp(pdp->ipd_name, "deprecated") == 0)
+			on = (ifflags & IFF_DEPRECATED);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	nbytes = snprintf(buf, *bufsize, "%s",
+	    (on ? IPADM_ONSTR : IPADM_OFFSTR));
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		status = IPADM_NO_BUFS;
+	}
+
+	return (status);
+}
+
+/*
+ * Callback function that retrieves the value of the property `zone'
+ * for the address object in `arg'.
+ */
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
+    uint_t valtype)
+{
+	struct lifreq	lifr;
+	char		zone_name[ZONENAME_MAX];
+	int		s;
+	size_t		nbytes = 0;
+
+	if (getzoneid() != GLOBAL_ZONEID) {
+		buf[0] = '\0';
+		return (IPADM_SUCCESS);
+	}
+
+	/*
+	 * we are in global zone. See if the lifname is assigned to shared-ip
+	 * zone or global zone.
+	 */
+	switch (valtype) {
+	case MOD_PROP_DEFAULT:
+		if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
+		    sizeof (zone_name)) > 0)
+			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
+		else
+			return (ipadm_errno2status(errno));
+		break;
+	case MOD_PROP_ACTIVE:
+		bzero(&lifr, sizeof (lifr));
+		i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
+		    sizeof (lifr.lifr_name));
+		s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+
+		if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
+			return (ipadm_errno2status(errno));
+
+		if (lifr.lifr_zoneid == ALL_ZONES) {
+			nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
+		} else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
+		    sizeof (zone_name)) < 0) {
+			return (ipadm_errno2status(errno));
+		} else {
+			nbytes = snprintf(buf, *bufsize, "%s", zone_name);
+		}
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+static ipadm_prop_desc_t *
+i_ipadm_getpropdesc(const char *pname)
+{
+	int i;
+
+	for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
+		if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0)
+			return (&ipadm_addrprop_table[i]);
+	}
+	return (NULL);
+}
+
+/*
+ * Gets the value of the given address property `pname' for the address
+ * object with name `aobjname'.
+ */
+ipadm_status_t
+ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
+    uint_t *bufsize, const char *aobjname, uint_t valtype)
+{
+	struct ipadm_addrobj_s	ipaddr;
+	ipadm_status_t		status = IPADM_SUCCESS;
+	sa_family_t		af;
+	ipadm_prop_desc_t	*pdp = NULL;
+
+	if (iph == NULL || pname == NULL || buf == NULL ||
+	    bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* find the property in the property description table */
+	if ((pdp = i_ipadm_getpropdesc(pname)) == NULL)
+		return (IPADM_PROP_UNKNOWN);
+
+	/*
+	 * For the given aobjname, get the addrobj it represents and
+	 * retrieve the property value for that object.
+	 */
+	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
+	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
+		return (status);
+
+	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
+		return (IPADM_NOTSUP);
+	af = ipaddr.ipadm_af;
+
+	/*
+	 * Call the appropriate callback function to based on the field
+	 * that was asked for.
+	 */
+	switch (valtype) {
+	case IPADM_OPT_PERM:
+		status = i_ipadm_pd2permstr(pdp, buf, bufsize);
+		break;
+	case IPADM_OPT_ACTIVE:
+		if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
+			buf[0] = '\0';
+		} else {
+			status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
+			    af, MOD_PROP_ACTIVE);
+		}
+		break;
+	case IPADM_OPT_DEFAULT:
+		status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
+		    af, MOD_PROP_DEFAULT);
+		break;
+	case IPADM_OPT_POSSIBLE:
+		if (pdp->ipd_get_range != NULL) {
+			status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
+			    bufsize, af, MOD_PROP_POSSIBLE);
+			break;
+		}
+		buf[0] = '\0';
+		break;
+	case IPADM_OPT_PERSIST:
+		status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
+		    &ipaddr);
+		break;
+	default:
+		status = IPADM_INVALID_ARG;
+		break;
+	}
+
+	return (status);
+}
+
+/*
+ * Sets the value of the given address property `pname' to `pval' for the
+ * address object with name `aobjname'.
+ */
+ipadm_status_t
+ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
+    const char *pval, const char *aobjname, uint_t pflags)
+{
+	struct ipadm_addrobj_s	ipaddr;
+	sa_family_t		af;
+	ipadm_prop_desc_t	*pdp = NULL;
+	char			defbuf[MAXPROPVALLEN];
+	uint_t			defbufsize = MAXPROPVALLEN;
+	boolean_t 		reset = (pflags & IPADM_OPT_DEFAULT);
+	ipadm_status_t		status = IPADM_SUCCESS;
+
+	/* Check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
+	    pflags == IPADM_OPT_PERSIST ||
+	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
+	    (!reset && pval == NULL)) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* find the property in the property description table */
+	if ((pdp = i_ipadm_getpropdesc(pname)) == NULL)
+		return (IPADM_PROP_UNKNOWN);
+
+	if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
+		return (IPADM_NOTSUP);
+
+	/*
+	 * For the given aobjname, get the addrobj it represents and
+	 * set the property value for that object.
+	 */
+	i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
+	if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
+		return (status);
+
+	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
+		return (IPADM_OP_DISABLE_OBJ);
+
+	/* Persistent operation not allowed on a temporary object. */
+	if ((pflags & IPADM_OPT_PERSIST) &&
+	    !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
+		return (IPADM_TEMPORARY_OBJ);
+
+	/*
+	 * Currently, setting an address property on an address object of type
+	 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
+	 * in.ndpd retrieving the address properties from ipmgmtd for given
+	 * address object and then setting them on auto-configured addresses,
+	 * whenever in.ndpd gets a new prefix. This will be supported in
+	 * future releases.
+	 */
+	if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
+		return (IPADM_NOTSUP);
+
+	/*
+	 * Setting an address property on an address object that is
+	 * not present in active configuration is not supported.
+	 */
+	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
+		return (IPADM_NOTSUP);
+
+	af = ipaddr.ipadm_af;
+	if (reset) {
+		/*
+		 * If we were asked to reset the value, we need to fetch
+		 * the default value and set the default value.
+		 */
+		status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
+		    af, MOD_PROP_DEFAULT);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		pval = defbuf;
+	}
+	/* set the user provided or default property value */
+	status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	/*
+	 * If IPADM_OPT_PERSIST was set in `flags', we need to store
+	 * property and its value in persistent DB.
+	 */
+	if (pflags & IPADM_OPT_PERSIST) {
+		status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
+		    pflags);
+	}
+
+	return (status);
+}
+
+/*
+ * Remove the address specified by the address object in `addr'
+ * from kernel. If the address is on a non-zero logical interface, we do a
+ * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
+ * :: for IPv6.
+ */
+ipadm_status_t
+i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
+{
+	struct lifreq	lifr;
+	int		sock;
+	ipadm_status_t	status;
+
+	bzero(&lifr, sizeof (lifr));
+	i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
+	sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+	if (addr->ipadm_lifnum == 0) {
+		/*
+		 * Fake the deletion of the 0'th address by
+		 * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
+		 */
+		status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
+		    addr->ipadm_af, 0, IFF_UP);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
+		lifr.lifr_addr.ss_family = addr->ipadm_af;
+		if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+	} else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
+		return (ipadm_errno2status(errno));
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Extracts the IPv6 address from the nvlist in `nvl'.
+ */
+ipadm_status_t
+i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
+{
+	uint8_t	*addr6;
+	uint_t	n;
+
+	if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
+		return (IPADM_NOTFOUND);
+	assert(n == 16);
+	bcopy(addr6, in6_addr->s6_addr, n);
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Used to validate the given addrobj name string. Length of `aobjname'
+ * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
+ * alphabetic character and it can only contain alphanumeric characters.
+ */
+static boolean_t
+i_ipadm_is_user_aobjname_valid(const char *aobjname)
+{
+	const char	*cp;
+
+	if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
+	    !isalpha(*aobjname)) {
+		return (B_FALSE);
+	}
+	for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
+		;
+	return (*cp == '\0');
+}
+
+/*
+ * Computes the prefixlen for the given `addr' based on the netmask found using
+ * the order specified in /etc/nsswitch.conf. If not found, then the
+ * prefixlen is computed using the Classful subnetting semantics defined
+ * in RFC 791 for IPv4 and RFC 4291 for IPv6.
+ */
+static ipadm_status_t
+i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
+{
+	sa_family_t af = addr->ss_family;
+	struct sockaddr_storage mask;
+	struct sockaddr_in *m = (struct sockaddr_in *)&mask;
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
+	struct in_addr ia;
+	uint32_t prefixlen = 0;
+
+	switch (af) {
+	case AF_INET:
+		sin = SIN(addr);
+		ia.s_addr = ntohl(sin->sin_addr.s_addr);
+		get_netmask4(&ia, &m->sin_addr);
+		m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
+		m->sin_family = AF_INET;
+		prefixlen = mask2plen(&mask);
+		break;
+	case AF_INET6:
+		sin6 = SIN6(addr);
+		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+			prefixlen = 10;
+		else
+			prefixlen = 64;
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	*plen = prefixlen;
+	return (IPADM_SUCCESS);
+}
+
+static ipadm_status_t
+i_ipadm_resolve_addr(const char *name, sa_family_t af,
+    struct sockaddr_storage *ss)
+{
+	struct addrinfo hints, *ai;
+	int rc;
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
+	boolean_t is_mapped;
+
+	(void) memset(&hints, 0, sizeof (hints));
+	hints.ai_family = af;
+	hints.ai_flags = (AI_ALL | AI_V4MAPPED);
+	rc = getaddrinfo(name, NULL, &hints, &ai);
+	if (rc != 0) {
+		if (rc == EAI_NONAME)
+			return (IPADM_BAD_ADDR);
+		else
+			return (IPADM_FAILURE);
+	}
+	if (ai->ai_next != NULL) {
+		/* maps to more than one hostname */
+		freeaddrinfo(ai);
+		return (IPADM_BAD_HOSTNAME);
+	}
+	/* LINTED E_BAD_PTR_CAST_ALIGN */
+	is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
+	if (is_mapped) {
+		sin = SIN(ss);
+		sin->sin_family = AF_INET;
+		/* LINTED E_BAD_PTR_CAST_ALIGN */
+		IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
+		    &sin->sin_addr);
+	} else {
+		sin6 = SIN6(ss);
+		sin6->sin6_family = AF_INET6;
+		bcopy(ai->ai_addr, sin6, sizeof (*sin6));
+	}
+	freeaddrinfo(ai);
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * This takes a static address string <addr>[/<mask>] or a hostname
+ * and maps it to a single numeric IP address, consulting DNS if
+ * hostname was provided. If a specific address family was requested,
+ * an error is returned if the given hostname does not map to an address
+ * of the given family. Note that this function returns failure
+ * if the name maps to more than one IP address.
+ */
+ipadm_status_t
+ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
+{
+	char		*prefixlenstr;
+	uint32_t	prefixlen = 0;
+	char		*endp;
+	/*
+	 * We use (NI_MAXHOST + 5) because the longest possible
+	 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
+	 * or a maximum of 128 for IPv6 + '\0') chars
+	 */
+	char		addrstr[NI_MAXHOST + 5];
+	ipadm_status_t	status;
+
+	(void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
+	if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
+		*prefixlenstr++ = '\0';
+		errno = 0;
+		prefixlen = strtoul(prefixlenstr, &endp, 10);
+		if (errno != 0 || *endp != '\0')
+			return (IPADM_INVALID_ARG);
+		if ((af == AF_INET && prefixlen > IP_ABITS) ||
+		    (af == AF_INET6 && prefixlen > IPV6_ABITS))
+			return (IPADM_INVALID_ARG);
+	}
+
+	status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
+	if (status == IPADM_SUCCESS) {
+		(void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
+		    sizeof (ipaddr->ipadm_static_aname));
+		ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
+		ipaddr->ipadm_static_prefixlen = prefixlen;
+	}
+	return (status);
+}
+
+/*
+ * Set up tunnel destination address in ipaddr by contacting DNS.
+ * The function works similar to ipadm_set_addr().
+ * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
+ * if dst_addr resolves to more than one address. The caller has to verify
+ * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
+ */
+ipadm_status_t
+ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
+{
+	ipadm_status_t	status;
+
+	/* mask lengths are not meaningful for point-to-point interfaces. */
+	if (strchr(daddrstr, '/') != NULL)
+		return (IPADM_BAD_ADDR);
+
+	status = i_ipadm_resolve_addr(daddrstr, af,
+	    &ipaddr->ipadm_static_dst_addr);
+	if (status == IPADM_SUCCESS) {
+		(void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
+		    sizeof (ipaddr->ipadm_static_dname));
+	}
+	return (status);
+}
+
+/*
+ * Sets the interface ID in the address object `ipaddr' with the address
+ * in the string `interface_id'. This interface ID will be used when
+ * ipadm_create_addr() is called with `ipaddr' with address type
+ * set to IPADM_ADDR_IPV6_ADDRCONF.
+ */
+ipadm_status_t
+ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
+{
+	struct sockaddr_in6	*sin6;
+	char			*end;
+	char			*cp;
+	uint32_t		prefixlen;
+	char			addrstr[INET6_ADDRSTRLEN + 1];
+
+	if (ipaddr == NULL || interface_id == NULL ||
+	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
+		return (IPADM_INVALID_ARG);
+
+	(void) strlcpy(addrstr, interface_id, sizeof (addrstr));
+	if ((cp = strchr(addrstr, '/')) == NULL)
+		return (IPADM_INVALID_ARG);
+	*cp++ = '\0';
+	sin6 = &ipaddr->ipadm_intfid;
+	if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
+		errno = 0;
+		prefixlen = strtoul(cp, &end, 10);
+		if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
+			return (IPADM_INVALID_ARG);
+		sin6->sin6_family = AF_INET6;
+		ipaddr->ipadm_intfidlen = prefixlen;
+		return (IPADM_SUCCESS);
+	}
+	return (IPADM_INVALID_ARG);
+}
+
+/*
+ * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
+ */
+ipadm_status_t
+ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
+{
+	if (ipaddr == NULL ||
+	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
+		return (IPADM_INVALID_ARG);
+	ipaddr->ipadm_stateless = stateless;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
+ */
+ipadm_status_t
+ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
+{
+	if (ipaddr == NULL ||
+	    ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
+		return (IPADM_INVALID_ARG);
+	ipaddr->ipadm_stateful = stateful;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
+ * The field is used during the address creation with address
+ * type IPADM_ADDR_DHCP. It specifies if the interface should be set
+ * as a primary interface for getting dhcp global options from the DHCP server.
+ */
+ipadm_status_t
+ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
+{
+	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
+		return (IPADM_INVALID_ARG);
+	ipaddr->ipadm_primary = primary;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
+ * This field is used during the address creation with address type
+ * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
+ * should wait before returning while the dhcp address is being acquired
+ * by the dhcpagent.
+ * Possible values:
+ * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
+ * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
+ * - <integer>	   : Wait the specified number of seconds before returning.
+ */
+ipadm_status_t
+ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
+{
+	if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
+		return (IPADM_INVALID_ARG);
+	ipaddr->ipadm_wait = wait;
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
+ * If the `aobjname' already exists in the daemon's `aobjmap' then
+ * IPADM_ADDROBJ_EXISTS will be returned.
+ *
+ * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
+ * daemon will generate an `aobjname' for the given `ipaddr'.
+ */
+ipadm_status_t
+i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
+{
+	ipmgmt_aobjop_arg_t	larg;
+	ipmgmt_aobjop_rval_t	rval, *rvalp;
+	int			err;
+
+	bzero(&larg, sizeof (larg));
+	larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
+	(void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
+	    sizeof (larg.ia_aobjname));
+	(void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
+	    sizeof (larg.ia_ifname));
+	larg.ia_family = ipaddr->ipadm_af;
+
+	rvalp = &rval;
+	err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
+	    sizeof (rval), B_FALSE);
+	if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') {
+		/* copy the daemon generated `aobjname' into `ipadddr' */
+		(void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname,
+		    sizeof (ipaddr->ipadm_aobjname));
+	}
+	if (err == EEXIST)
+		return (IPADM_ADDROBJ_EXISTS);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
+ * `ifname'. If a hostname is present, it is resolved before the address
+ * is created.
+ */
+ipadm_status_t
+i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
+    sa_family_t af)
+{
+	char			*prefixlenstr = NULL;
+	char			*upstr = NULL;
+	char			*sname = NULL, *dname = NULL;
+	struct ipadm_addrobj_s	ipaddr;
+	char			*aobjname = NULL;
+	nvlist_t		*nvaddr = NULL;
+	nvpair_t		*nvp;
+	char			*cidraddr;
+	char			*name;
+	ipadm_status_t		status;
+	int			err = 0;
+	uint32_t		flags = IPADM_OPT_ACTIVE;
+
+	/* retrieve the address information */
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
+		    strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
+			err = nvpair_value_nvlist(nvp, &nvaddr);
+		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
+			err = nvpair_value_string(nvp, &aobjname);
+		} else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
+			err = nvpair_value_string(nvp, &prefixlenstr);
+		} else if (strcmp(name, "up") == 0) {
+			err = nvpair_value_string(nvp, &upstr);
+		}
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
+			err = nvpair_value_string(nvp, &sname);
+		else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
+			err = nvpair_value_string(nvp, &dname);
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+
+	if (strcmp(upstr, "yes") == 0)
+		flags |= IPADM_OPT_UP;
+
+	/* build the address object from the above information */
+	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
+	if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
+		if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
+			return (IPADM_NO_MEMORY);
+		status = ipadm_set_addr(&ipaddr, cidraddr, af);
+		free(cidraddr);
+	} else {
+		status = ipadm_set_addr(&ipaddr, sname, af);
+	}
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (dname != NULL) {
+		status = ipadm_set_dst_addr(&ipaddr, dname, af);
+		if (status != IPADM_SUCCESS)
+			return (status);
+	}
+	return (i_ipadm_create_addr(iph, &ipaddr, flags));
+}
+
+/*
+ * Creates a dhcp address on the interface `ifname' based on the
+ * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
+ */
+ipadm_status_t
+i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
+{
+	int32_t			wait;
+	boolean_t		primary;
+	nvlist_t		*nvdhcp;
+	nvpair_t		*nvp;
+	char			*name;
+	struct ipadm_addrobj_s	ipaddr;
+	char			*aobjname;
+	int			err = 0;
+
+	/* Extract the dhcp parameters */
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_DHCP) == 0)
+			err = nvpair_value_nvlist(nvp, &nvdhcp);
+		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
+			err = nvpair_value_string(nvp, &aobjname);
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+	for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_WAIT) == 0)
+			err = nvpair_value_int32(nvp, &wait);
+		else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
+			err = nvpair_value_boolean_value(nvp, &primary);
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+
+	/* Build the address object */
+	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
+	ipaddr.ipadm_primary = primary;
+	if (iph->iph_flags & IPH_INIT)
+		ipaddr.ipadm_wait = 0;
+	else
+		ipaddr.ipadm_wait = wait;
+	return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
+}
+
+/*
+ * Creates auto-configured addresses on the interface `ifname' based on
+ * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
+ */
+ipadm_status_t
+i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
+{
+	struct ipadm_addrobj_s	ipaddr;
+	char		*stateful = NULL, *stateless = NULL;
+	uint_t		n;
+	uint8_t		*addr6 = NULL;
+	uint32_t	intfidlen = 0;
+	char		*aobjname;
+	nvlist_t	*nvaddr;
+	nvpair_t	*nvp;
+	char		*name;
+	int		err = 0;
+
+	/* Extract the parameters */
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_INTFID) == 0)
+			err = nvpair_value_nvlist(nvp, &nvaddr);
+		else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
+			err = nvpair_value_string(nvp, &aobjname);
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+	for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvaddr, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
+			err = nvpair_value_uint8_array(nvp, &addr6, &n);
+		if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
+			err = nvpair_value_uint32(nvp, &intfidlen);
+		else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
+			err = nvpair_value_string(nvp, &stateless);
+		else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
+			err = nvpair_value_string(nvp, &stateful);
+		if (err != 0)
+			return (ipadm_errno2status(err));
+	}
+	/* Build the address object. */
+	i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
+	if (intfidlen > 0) {
+		ipaddr.ipadm_intfidlen = intfidlen;
+		bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
+	}
+	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
+	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
+	return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
+}
+
+/*
+ * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
+ * the provided `type'. `aobjname' represents the address object name, which
+ * is of the form `<ifname>/<addressname>'.
+ *
+ * The caller has to minimally provide <ifname>. If <addressname> is not
+ * provided, then a default one will be generated by the API.
+ */
+ipadm_status_t
+ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
+    ipadm_addrobj_t *ipaddr)
+{
+	ipadm_addrobj_t	newaddr;
+	ipadm_status_t	status;
+	char		*aname, *cp;
+	char		ifname[IPADM_AOBJSIZ];
+	ifspec_t 	ifsp;
+
+	if (ipaddr == NULL)
+		return (IPADM_INVALID_ARG);
+	*ipaddr = NULL;
+
+	if (aobjname == NULL || aobjname[0] == '\0')
+		return (IPADM_INVALID_ARG);
+
+	if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
+		return (IPADM_INVALID_ARG);
+
+	if ((aname = strchr(ifname, '/')) != NULL)
+		*aname++ = '\0';
+
+	/* Check if the interface name is valid. */
+	if (!ifparse_ifspec(ifname, &ifsp))
+		return (IPADM_INVALID_ARG);
+
+	/* Check if the given addrobj name is valid. */
+	if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
+		return (IPADM_INVALID_ARG);
+
+	if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
+		return (IPADM_NO_MEMORY);
+
+	/*
+	 * If the ifname has logical interface number, extract it and assign
+	 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
+	 * this today. We will check for the validity later in
+	 * i_ipadm_validate_create_addr().
+	 */
+	if (ifsp.ifsp_lunvalid) {
+		newaddr->ipadm_lifnum = ifsp.ifsp_lun;
+		cp = strchr(ifname, IPADM_LOGICAL_SEP);
+		*cp = '\0';
+	}
+	(void) strlcpy(newaddr->ipadm_ifname, ifname,
+	    sizeof (newaddr->ipadm_ifname));
+
+	if (aname != NULL) {
+		(void) snprintf(newaddr->ipadm_aobjname,
+		    sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
+	}
+
+	switch (type) {
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		newaddr->ipadm_intfidlen = 0;
+		newaddr->ipadm_stateful = B_TRUE;
+		newaddr->ipadm_stateless = B_TRUE;
+		newaddr->ipadm_af = AF_INET6;
+		break;
+
+	case IPADM_ADDR_DHCP:
+		newaddr->ipadm_primary = B_FALSE;
+		newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
+		newaddr->ipadm_af = AF_INET;
+		break;
+
+		case IPADM_ADDR_STATIC:
+			newaddr->ipadm_af = AF_UNSPEC;
+			newaddr->ipadm_static_prefixlen = 0;
+			break;
+		default:
+			status = IPADM_INVALID_ARG;
+			goto fail;
+	}
+	newaddr->ipadm_atype = type;
+	*ipaddr = newaddr;
+	return (IPADM_SUCCESS);
+fail:
+	free(newaddr);
+	return (status);
+}
+
+/*
+ * Frees the address object in `ipaddr'.
+ */
+void
+ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
+{
+	free(ipaddr);
+}
+
+/*
+ * Retrieves the logical interface name from `ipaddr' and stores the
+ * string in `lifname'.
+ */
+void
+i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
+{
+	if (ipaddr->ipadm_lifnum != 0) {
+		(void) snprintf(lifname, lifnamesize, "%s:%d",
+		    ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
+	} else {
+		(void) snprintf(lifname, lifnamesize, "%s",
+		    ipaddr->ipadm_ifname);
+	}
+}
+
+/*
+ * Checks if a non-zero static address is present on the 0th logical interface
+ * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
+ * also checks if the interface is under DHCP control. If the condition is true,
+ * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
+ * is set to B_FALSE.
+ */
+static ipadm_status_t
+i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
+    sa_family_t af, boolean_t *exists)
+{
+	struct lifreq	lifr;
+	int		sock;
+
+	/* For IPH_LEGACY, a new logical interface will never be added. */
+	if (iph->iph_flags & IPH_LEGACY) {
+		*exists = B_FALSE;
+		return (IPADM_SUCCESS);
+	}
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (af == AF_INET) {
+		sock = iph->iph_sock;
+		if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		if (lifr.lifr_flags & IFF_DHCPRUNNING) {
+			*exists = B_TRUE;
+			return (IPADM_SUCCESS);
+		}
+	} else {
+		sock = iph->iph_sock6;
+	}
+	if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+	*exists = !sockaddrunspec(&lifr.lifr_addr);
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Reads all the address lines from the persistent DB into the nvlist `onvl',
+ * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
+ * it returns all the addresses for the given interface `ifname'.
+ * If an `aobjname' is specified, then the address line corresponding to
+ * that name will be returned.
+ */
+static ipadm_status_t
+i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
+    const char *aobjname, nvlist_t **onvl)
+{
+	ipmgmt_getaddr_arg_t	garg;
+	ipmgmt_get_rval_t	*rvalp;
+	int			err;
+	size_t			nvlsize;
+	char			*nvlbuf;
+
+	/* Populate the door_call argument structure */
+	bzero(&garg, sizeof (garg));
+	garg.ia_cmd = IPMGMT_CMD_GETADDR;
+	if (aobjname != NULL)
+		(void) strlcpy(garg.ia_aobjname, aobjname,
+		    sizeof (garg.ia_aobjname));
+	if (ifname != NULL)
+		(void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
+
+	rvalp = malloc(sizeof (ipmgmt_get_rval_t));
+	err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
+	    sizeof (*rvalp), B_TRUE);
+	if (err == 0) {
+		nvlsize = rvalp->ir_nvlsize;
+		nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
+		err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
+	}
+	free(rvalp);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Adds the IP address contained in the 'ipaddr' argument to the physical
+ * interface represented by 'ifname' after doing the required validation.
+ * If the interface does not exist, it is created before the address is
+ * added.
+ *
+ * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
+ * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
+ * if provided, will be ignored and replaced with the newly generated name.
+ * The interface name provided has to be a logical interface name that
+ * already exists. No new logical interface will be added in this function.
+ */
+ipadm_status_t
+ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
+{
+	ipadm_status_t		status;
+	sa_family_t		af;
+	sa_family_t		daf;
+	sa_family_t		other_af;
+	boolean_t		created_af = B_FALSE;
+	boolean_t		created_other_af = B_FALSE;
+	ipadm_addr_type_t	type;
+	char			*ifname = addr->ipadm_ifname;
+	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
+	boolean_t		aobjfound;
+	boolean_t		is_6to4;
+	struct lifreq		lifr;
+	uint64_t		ifflags;
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* Validate the addrobj. This also fills in addr->ipadm_ifname. */
+	status = i_ipadm_validate_create_addr(iph, addr, flags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	/*
+	 * For Legacy case, check if an addrobj already exists for the
+	 * given logical interface name. If one does not exist,
+	 * a default name will be generated and added to the daemon's
+	 * aobjmap.
+	 */
+	if (legacy) {
+		struct ipadm_addrobj_s	ipaddr;
+
+		ipaddr = *addr;
+		status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
+		if (status == IPADM_SUCCESS) {
+			aobjfound = B_TRUE;
+			/*
+			 * With IPH_LEGACY, modifying an address that is not
+			 * a static address will return with an error.
+			 */
+			if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
+				return (IPADM_NOTSUP);
+			/*
+			 * we found the addrobj in daemon, copy over the
+			 * aobjname to `addr'.
+			 */
+			(void) strlcpy(addr->ipadm_aobjname,
+			    ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
+		} else if (status == IPADM_NOTFOUND) {
+			aobjfound = B_FALSE;
+		} else {
+			return (status);
+		}
+	}
+
+	af = addr->ipadm_af;
+	/*
+	 * Create a placeholder for this address object in the daemon.
+	 * Skip this step for IPH_LEGACY case if the addrobj already
+	 * exists.
+	 */
+	if (!legacy || !aobjfound) {
+		status = i_ipadm_lookupadd_addrobj(iph, addr);
+		if (status != IPADM_SUCCESS)
+			return (status);
+	}
+
+	is_6to4 = i_ipadm_is_6to4(iph, ifname);
+	/* Plumb the IP interfaces if necessary */
+	status = i_ipadm_create_if(iph, ifname, af, flags);
+	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
+		(void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
+		return (status);
+	}
+	if (status == IPADM_SUCCESS)
+		created_af = B_TRUE;
+	if (!is_6to4 && !legacy) {
+		other_af = (af == AF_INET ? AF_INET6 : AF_INET);
+		status = i_ipadm_create_if(iph, ifname, other_af, flags);
+		if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
+			(void) i_ipadm_delete_if(iph, ifname, af, flags);
+			return (status);
+		}
+		if (status == IPADM_SUCCESS)
+			created_other_af = B_TRUE;
+	}
+
+	/* Validate static addresses for IFF_POINTOPOINT interfaces. */
+	if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
+		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
+		if (status != IPADM_SUCCESS)
+			goto fail;
+		daf = addr->ipadm_static_dst_addr.ss_family;
+		if (ifflags & IFF_POINTOPOINT) {
+			if (is_6to4) {
+				if (af != AF_INET6 || daf != AF_UNSPEC) {
+					status = IPADM_INVALID_ARG;
+					goto fail;
+				}
+			} else {
+				if (daf != af) {
+					status = IPADM_INVALID_ARG;
+					goto fail;
+				}
+				/* Check for a valid dst address. */
+				if (!legacy && sockaddrunspec(
+				    &addr->ipadm_static_dst_addr)) {
+					status = IPADM_BAD_ADDR;
+					goto fail;
+				}
+			}
+		} else {
+			/*
+			 * Disallow setting of dstaddr when the link is not
+			 * a point-to-point link.
+			 */
+			if (daf != AF_UNSPEC)
+				return (IPADM_INVALID_ARG);
+		}
+	}
+
+	/*
+	 * For 6to4 interfaces, kernel configures a default link-local
+	 * address. We need to replace it, if the caller has provided
+	 * an address that is different from the default link-local.
+	 */
+	if (status == IPADM_SUCCESS && is_6to4) {
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
+			status = ipadm_errno2status(errno);
+			goto fail;
+		}
+		if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
+			return (IPADM_SUCCESS);
+	}
+
+	/* Create the address. */
+	type = addr->ipadm_atype;
+	switch (type) {
+	case IPADM_ADDR_STATIC:
+		status = i_ipadm_create_addr(iph, addr, flags);
+		break;
+	case IPADM_ADDR_DHCP:
+		status = i_ipadm_create_dhcp(iph, addr, flags);
+		break;
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		status = i_ipadm_create_ipv6addrs(iph, addr, flags);
+		break;
+	default:
+		status = IPADM_INVALID_ARG;
+		break;
+	}
+
+	/*
+	 * If address was not created successfully, unplumb the interface
+	 * if it was plumbed implicitly in this function and remove the
+	 * addrobj created by the ipmgmtd daemon as a placeholder.
+	 * If IPH_LEGACY is set, then remove the addrobj only if it was
+	 * created in this function.
+	 */
+fail:
+	if (status != IPADM_DHCP_IPC_TIMEOUT &&
+	    status != IPADM_SUCCESS) {
+		if (!legacy) {
+			if (created_af || created_other_af) {
+				if (created_af) {
+					(void) i_ipadm_delete_if(iph, ifname,
+					    af, flags);
+				}
+				if (created_other_af) {
+					(void) i_ipadm_delete_if(iph, ifname,
+					    other_af, flags);
+				}
+			} else {
+				(void) i_ipadm_delete_addrobj(iph, addr, flags);
+			}
+		} else if (!aobjfound) {
+			(void) i_ipadm_delete_addrobj(iph, addr, flags);
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * Creates the static address in `ipaddr' in kernel. After successfully
+ * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
+ * interface information.
+ */
+static ipadm_status_t
+i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
+{
+	struct lifreq			lifr;
+	ipadm_status_t			status = IPADM_SUCCESS;
+	int				sock;
+	struct sockaddr_storage		m, *mask = &m;
+	const struct sockaddr_storage	*addr = &ipaddr->ipadm_static_addr;
+	const struct sockaddr_storage	*daddr = &ipaddr->ipadm_static_dst_addr;
+	sa_family_t			af;
+	boolean_t			addif;
+	boolean_t			legacy = (iph->iph_flags & IPH_LEGACY);
+	struct ipadm_addrobj_s		legacy_addr;
+	boolean_t			default_prefixlen = B_FALSE;
+
+	af = ipaddr->ipadm_af;
+	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+
+	/* If prefixlen was not provided, get default prefixlen */
+	if (ipaddr->ipadm_static_prefixlen == 0) {
+		/* prefixlen was not provided, get default prefixlen */
+		status = i_ipadm_get_default_prefixlen(
+		    &ipaddr->ipadm_static_addr,
+		    &ipaddr->ipadm_static_prefixlen);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		default_prefixlen = B_TRUE;
+	}
+	(void) plen2mask(ipaddr->ipadm_static_prefixlen, af, mask);
+
+	/*
+	 * Check if the interface already has a non-zero address on 0th lif.
+	 * It it does, we create a new logical interface and add the address
+	 * on the new logical interface. If not, we replace the zero address
+	 * on 0th logical interface with the given address.
+	 */
+	status = i_ipadm_addr_exists_on_if(iph, ipaddr->ipadm_ifname, af,
+	    &addif);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	/*
+	 * This is a "hack" to get around the problem of SIOCLIFADDIF. The
+	 * problem is that this ioctl does not include the netmask when adding
+	 * a logical interface.
+	 *
+	 * To get around this problem, we first add the logical interface with
+	 * a 0 address.  After that, we set the netmask if provided.  Finally
+	 * we set the interface address.
+	 */
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ipaddr->ipadm_ifname,
+	    sizeof (lifr.lifr_name));
+	if (addif) {
+		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		ipaddr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
+	} else if (!legacy) {
+		/*
+		 * If IPH_LEGACY is specified, the input logical interface
+		 * number is already available in ipadm_lifnum.
+		 */
+		ipaddr->ipadm_lifnum = 0;
+	}
+	i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
+	    sizeof (lifr.lifr_name));
+	lifr.lifr_addr = *mask;
+	if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
+		status = ipadm_errno2status(errno);
+		goto ret;
+	}
+	lifr.lifr_addr = *addr;
+	if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
+		status = ipadm_errno2status(errno);
+		goto ret;
+	}
+	/* Set the destination address, if one is given. */
+	if (daddr->ss_family != AF_UNSPEC) {
+		lifr.lifr_addr = *daddr;
+		if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
+			status = ipadm_errno2status(errno);
+			goto ret;
+		}
+	}
+
+	if (flags & IPADM_OPT_UP) {
+		status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
+
+		/*
+		 * IPADM_DAD_FOUND is a soft-error for create-addr.
+		 * No need to tear down the address.
+		 */
+		if (status == IPADM_DAD_FOUND)
+			status = IPADM_SUCCESS;
+	}
+
+	if (status == IPADM_SUCCESS) {
+		/*
+		 * For IPH_LEGACY, we might be modifying the address on
+		 * an address object that already exists e.g. by doing
+		 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
+		 * So, we need to store the object only if it does not
+		 * already exist in ipmgmtd.
+		 */
+		if (legacy) {
+			bzero(&legacy_addr, sizeof (legacy_addr));
+			(void) strlcpy(legacy_addr.ipadm_aobjname,
+			    ipaddr->ipadm_aobjname,
+			    sizeof (legacy_addr.ipadm_aobjname));
+			status = i_ipadm_get_addrobj(iph, &legacy_addr);
+			if (status == IPADM_SUCCESS &&
+			    legacy_addr.ipadm_lifnum >= 0) {
+				return (status);
+			}
+		}
+		status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
+		    flags);
+	}
+ret:
+	if (status != IPADM_SUCCESS && !legacy)
+		(void) i_ipadm_delete_addr(iph, ipaddr);
+	return (status);
+}
+
+/*
+ * Removes the address object identified by `aobjname' from both active and
+ * persistent configuration. The address object will be removed from only
+ * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
+ *
+ * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
+ * in the address object will be removed from the physical interface.
+ * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
+ * whether the lease should be released. If IPADM_OPT_RELEASE is not
+ * specified, the lease will be dropped. This option is ignored
+ * for other address types.
+ *
+ * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
+ * all the autoconfigured addresses will be removed.
+ * Finally, the address object is also removed from ipmgmtd's aobjmap and from
+ * the persistent DB.
+ */
+ipadm_status_t
+ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
+{
+	ipadm_status_t		status;
+	struct ipadm_addrobj_s	ipaddr;
+	boolean_t		release = ((flags & IPADM_OPT_RELEASE) != 0);
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* validate input */
+	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
+	    !(flags & IPADM_OPT_ACTIVE)) ||
+	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
+		return (IPADM_INVALID_ARG);
+	}
+	bzero(&ipaddr, sizeof (ipaddr));
+	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
+	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* Retrieve the address object information from ipmgmtd. */
+	status = i_ipadm_get_addrobj(iph, &ipaddr);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
+		return (IPADM_NOTSUP);
+	/*
+	 * If requested to delete 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);
+	}
+
+	/*
+	 * If address is present in active config, remove it from
+	 * kernel.
+	 */
+	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
+		switch (ipaddr.ipadm_atype) {
+		case IPADM_ADDR_STATIC:
+			status = i_ipadm_delete_addr(iph, &ipaddr);
+			break;
+		case IPADM_ADDR_DHCP:
+			status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
+			break;
+		case IPADM_ADDR_IPV6_ADDRCONF:
+			status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
+			break;
+		default:
+			/*
+			 * This is the case of address object name residing in
+			 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
+			 * through and delete that address object.
+			 */
+			break;
+		}
+
+		/*
+		 * If the address was previously deleted from the active
+		 * config, we will get a IPADM_ENXIO from kernel.
+		 * We will still proceed and purge the address information
+		 * in the DB.
+		 */
+		if (status == IPADM_ENXIO)
+			status = IPADM_SUCCESS;
+		else if (status != IPADM_SUCCESS)
+			return (status);
+	}
+
+	if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
+	    (flags & IPADM_OPT_PERSIST)) {
+		flags &= ~IPADM_OPT_PERSIST;
+	}
+	status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
+	if (status == IPADM_NOTFOUND)
+		return (status);
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Starts the dhcpagent and sends it the message DHCP_START to start
+ * configuring a dhcp address on the given interface in `addr'.
+ * After making the dhcpagent request, it also updates the
+ * address object information in ipmgmtd's aobjmap and creates an
+ * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
+ */
+static ipadm_status_t
+i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
+{
+	struct lifreq	lifr;
+	int		sock = iph->iph_sock;
+	ipadm_status_t	status;
+	ipadm_status_t	dh_status;
+	boolean_t	addif;
+
+	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
+		return (IPADM_DHCP_START_ERROR);
+	/*
+	 * Check if a new logical interface has to be created.
+	 */
+	addr->ipadm_lifnum = 0;
+	status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname, AF_INET,
+	    &addif);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	if (addif) {
+		/*
+		 * If there is an address on 0th logical interface,
+		 * add a new logical interface.
+		 */
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
+	}
+	/* Send DHCP_START to the dhcpagent. */
+	status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
+	/*
+	 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
+	 * since it is only a soft error to indicate the caller that the lease
+	 * might be required after the function returns.
+	 */
+	if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
+		goto fail;
+	dh_status = status;
+
+	/* Persist the address object information in ipmgmtd. */
+	status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags);
+	if (status != IPADM_SUCCESS)
+		goto fail;
+
+	return (dh_status);
+fail:
+	/* In case of error, delete the dhcp address */
+	(void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
+	return (status);
+}
+
+/*
+ * Releases/drops the dhcp lease on the logical interface in the address
+ * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
+ */
+static ipadm_status_t
+i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
+{
+	ipadm_status_t	status;
+	int		dherr;
+
+	/* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
+	if (release) {
+		status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
+		/*
+		 * If no lease was obtained on the object, we should
+		 * drop the dhcp control on the interface.
+		 */
+		if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
+			status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
+	} else {
+		status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
+	}
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	/* Delete the logical interface */
+	if (addr->ipadm_lifnum != 0) {
+		struct lifreq lifr;
+
+		bzero(&lifr, sizeof (lifr));
+		i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
+		    sizeof (lifr.lifr_name));
+		if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Communicates with the dhcpagent to send a dhcp message of type `type'.
+ * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
+ * in `dhcperror'.
+ */
+static ipadm_status_t
+i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
+{
+	dhcp_ipc_request_t	*request;
+	dhcp_ipc_reply_t	*reply	= NULL;
+	char			ifname[LIFNAMSIZ];
+	int			error;
+	int			dhcp_timeout;
+
+	/* Construct a message to the dhcpagent. */
+	bzero(&ifname, sizeof (ifname));
+	i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
+	if (addr->ipadm_primary)
+		type |= DHCP_PRIMARY;
+	request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE);
+	if (request == NULL)
+		return (IPADM_NO_MEMORY);
+
+	if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
+		dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
+	else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
+		dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
+	else
+		dhcp_timeout = addr->ipadm_wait;
+	/* Send the message to dhcpagent. */
+	error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
+	free(request);
+	if (error == 0) {
+		error = reply->return_code;
+		free(reply);
+	}
+	if (error != 0) {
+		if (dhcperror != NULL)
+			*dhcperror = error;
+		if (error != DHCP_IPC_E_TIMEOUT)
+			return (IPADM_DHCP_IPC_ERROR);
+		else if (dhcp_timeout != 0)
+			return (IPADM_DHCP_IPC_TIMEOUT);
+	}
+
+	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
+ * configured on all interfaces in active and persistent
+ * configurations.
+ * `addrinfo' will contain addresses that are
+ * (1) in both active and persistent configuration (created persistently)
+ * (2) only in active configuration (created temporarily)
+ * (3) only in persistent configuration (disabled addresses)
+ *
+ * Address list that is returned by this function must be freed
+ * using the ipadm_freeaddr_info() function.
+ */
+ipadm_status_t
+ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
+{
+	ifspec_t	ifsp;
+
+	if (addrinfo == NULL || iph == NULL)
+		return (IPADM_INVALID_ARG);
+	if (ifname != NULL &&
+	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
+		return (IPADM_INVALID_ARG);
+	}
+	return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
+	    flags, lifc_flags));
+}
+
+/*
+ * Frees the structure allocated by ipadm_addr_info().
+ */
+void
+ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
+{
+	freeifaddrs((struct ifaddrs *)ainfo);
+}
+
+/*
+ * Makes a door call to ipmgmtd to update its `aobjmap' with the address
+ * object in `ipaddr'. This door call also updates the persistent DB to
+ * remember address object to be recreated on next reboot or on an
+ * ipadm_enable_addr()/ipadm_enable_if() call.
+ */
+ipadm_status_t
+i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
+    boolean_t default_prefixlen, uint32_t flags)
+{
+	char			*aname = ipaddr->ipadm_aobjname;
+	nvlist_t		*nvl;
+	int			err = 0;
+	ipadm_status_t		status;
+	char			pval[MAXPROPVALLEN];
+	uint_t			pflags = 0;
+	ipadm_prop_desc_t	*pdp = NULL;
+
+	/*
+	 * Construct the nvl to send to the door.
+	 */
+	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+		return (IPADM_NO_MEMORY);
+	if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
+	    ipaddr->ipadm_ifname)) != 0 ||
+	    (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
+	    (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
+	    ipaddr->ipadm_lifnum)) != 0) {
+		status = ipadm_errno2status(err);
+		goto ret;
+	}
+	switch (ipaddr->ipadm_atype) {
+	case IPADM_ADDR_STATIC:
+		status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
+		if (status != IPADM_SUCCESS)
+			goto ret;
+		(void) snprintf(pval, sizeof (pval), "%d",
+		    ipaddr->ipadm_static_prefixlen);
+		if (flags & IPADM_OPT_UP)
+			err = nvlist_add_string(nvl, "up", "yes");
+		else
+			err = nvlist_add_string(nvl, "up", "no");
+		status = ipadm_errno2status(err);
+		break;
+	case IPADM_ADDR_DHCP:
+		status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
+		    ipaddr->ipadm_wait);
+		break;
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
+		break;
+	}
+	if (status != IPADM_SUCCESS)
+		goto ret;
+
+	if (iph->iph_flags & IPH_INIT) {
+		/*
+		 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
+		 * IPMGMT_PERSIST on the address object in its `aobjmap'.
+		 * For the callers ipadm_enable_if() and ipadm_enable_addr(),
+		 * IPADM_OPT_PERSIST is not set in their flags. They send
+		 * IPH_INIT in iph_flags, so that the address object will be
+		 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
+		 */
+		pflags |= IPMGMT_INIT;
+	} else {
+		if (flags & IPADM_OPT_ACTIVE)
+			pflags |= IPMGMT_ACTIVE;
+		if (flags & IPADM_OPT_PERSIST)
+			pflags |= IPMGMT_PERSIST;
+	}
+	status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
+	/*
+	 * prefixlen is stored in a separate line in the DB and not along
+	 * with the address itself, since it is also an address property and
+	 * all address properties are stored in separate lines. We need to
+	 * persist the prefixlen by calling the function that persists
+	 * address properties.
+	 */
+	if (status == IPADM_SUCCESS && !default_prefixlen &&
+	    ipaddr->ipadm_atype == IPADM_ADDR_STATIC &&
+	    (flags & IPADM_OPT_PERSIST)) {
+		for (pdp = ipadm_addrprop_table; pdp->ipd_name != NULL; pdp++) {
+			if (strcmp("prefixlen", pdp->ipd_name) == 0)
+				break;
+		}
+		assert(pdp != NULL);
+		status = i_ipadm_persist_propval(iph, pdp, pval, ipaddr, flags);
+	}
+ret:
+	nvlist_free(nvl);
+	return (status);
+}
+
+/*
+ * Makes the door call to ipmgmtd to store the address object in the
+ * nvlist `nvl'.
+ */
+static ipadm_status_t
+i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
+{
+	char			*buf = NULL, *nvlbuf = NULL;
+	size_t			nvlsize, bufsize;
+	ipmgmt_setaddr_arg_t	*sargp;
+	int			err;
+
+	err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
+	if (err != 0)
+		return (ipadm_errno2status(err));
+	bufsize = sizeof (*sargp) + nvlsize;
+	buf = calloc(1, bufsize);
+	sargp = (void *)buf;
+	sargp->ia_cmd = IPMGMT_CMD_SETADDR;
+	sargp->ia_flags = flags;
+	sargp->ia_nvlsize = nvlsize;
+	(void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
+	err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
+	free(buf);
+	free(nvlbuf);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
+ * from its `aobjmap'. This door call also removes the address object and all
+ * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
+ * `flags', so that the object will not be recreated on next reboot or on an
+ * ipadm_enable_addr()/ipadm_enable_if() call.
+ */
+ipadm_status_t
+i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
+    uint32_t flags)
+{
+	ipmgmt_addr_arg_t	arg;
+	int			err;
+
+	arg.ia_cmd = IPMGMT_CMD_RESETADDR;
+	arg.ia_flags = 0;
+	if (flags & IPADM_OPT_ACTIVE)
+		arg.ia_flags |= IPMGMT_ACTIVE;
+	if (flags & IPADM_OPT_PERSIST)
+		arg.ia_flags |= IPMGMT_PERSIST;
+	(void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
+	    sizeof (arg.ia_aobjname));
+	arg.ia_lnum = ipaddr->ipadm_lifnum;
+	err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Checks if the caller is authorized for the up/down operation.
+ * Retrieves the address object corresponding to `aobjname' from ipmgmtd
+ * and retrieves the address flags for that object from kernel.
+ * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
+ */
+static ipadm_status_t
+i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
+    ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
+{
+	ipadm_status_t	status;
+	char		lifname[LIFNAMSIZ];
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* validate input */
+	if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
+	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* Retrieve the address object information. */
+	status = i_ipadm_get_addrobj(iph, ipaddr);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
+		return (IPADM_OP_DISABLE_OBJ);
+	if ((ipadm_flags & IPADM_OPT_PERSIST) &&
+	    !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
+		return (IPADM_TEMPORARY_OBJ);
+	if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
+	    (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
+	    (ipadm_flags & IPADM_OPT_PERSIST)))
+		return (IPADM_NOTSUP);
+
+	i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
+	return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
+}
+
+/*
+ * Marks the address in the address object `aobjname' up. This operation is
+ * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
+ * For an address object of type IPADM_ADDR_DHCP, this operation can
+ * only be temporary and no updates will be made to the persistent DB.
+ */
+ipadm_status_t
+ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
+{
+	struct ipadm_addrobj_s ipaddr;
+	ipadm_status_t	status;
+	uint64_t	flags;
+	char		lifname[LIFNAMSIZ];
+
+	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
+	    &flags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	if (flags & IFF_UP)
+		goto persist;
+	/*
+	 * If the address is already a duplicate, then refresh-addr
+	 * should be used to mark it up.
+	 */
+	if (flags & IFF_DUPLICATE)
+		return (IPADM_DAD_FOUND);
+
+	i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
+	status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+persist:
+	/* Update persistent DB. */
+	if (ipadm_flags & IPADM_OPT_PERSIST) {
+		status = i_ipadm_persist_propval(iph, &up_addrprop,
+		    "yes", &ipaddr, 0);
+	}
+
+	return (status);
+}
+
+/*
+ * Marks the address in the address object `aobjname' down. This operation is
+ * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
+ * For an address object of type IPADM_ADDR_DHCP, this operation can
+ * only be temporary and no updates will be made to the persistent DB.
+ */
+ipadm_status_t
+ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
+{
+	struct ipadm_addrobj_s ipaddr;
+	ipadm_status_t	status;
+	struct lifreq	lifr;
+	uint64_t	flags;
+
+	status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
+	    &flags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
+	    sizeof (lifr.lifr_name));
+	if (flags & IFF_UP) {
+		status = i_ipadm_set_flags(iph, lifr.lifr_name,
+		    ipaddr.ipadm_af, 0, IFF_UP);
+		if (status != IPADM_SUCCESS)
+			return (status);
+	} else if (flags & IFF_DUPLICATE) {
+		/*
+		 * Clear the IFF_DUPLICATE flag.
+		 */
+		if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
+			return (ipadm_errno2status(errno));
+		if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
+			return (ipadm_errno2status(errno));
+	}
+
+	/* Update persistent DB */
+	if (ipadm_flags & IPADM_OPT_PERSIST) {
+		status = i_ipadm_persist_propval(iph, &up_addrprop,
+		    "no", &ipaddr, 0);
+	}
+
+	return (status);
+}
+
+/*
+ * Refreshes the address in the address object `aobjname'. If the address object
+ * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
+ * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
+ * dhcpagent for this static address. If the address object is of type
+ * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
+ * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
+ * dhcpagent. This operation is not supported for an address object of
+ * type IPADM_ADDR_IPV6_ADDRCONF.
+ */
+ipadm_status_t
+ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
+    uint32_t ipadm_flags)
+{
+	ipadm_status_t		status = IPADM_SUCCESS;
+	uint64_t		flags;
+	struct ipadm_addrobj_s	ipaddr;
+	sa_family_t		af;
+	char			lifname[LIFNAMSIZ];
+	boolean_t		inform =
+	    ((ipadm_flags & IPADM_OPT_INFORM) != 0);
+	int			dherr;
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* validate input */
+	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
+	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* Retrieve the address object information. */
+	status = i_ipadm_get_addrobj(iph, &ipaddr);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
+		return (IPADM_OP_DISABLE_OBJ);
+
+	if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
+		return (IPADM_NOTSUP);
+	if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
+		return (IPADM_INVALID_ARG);
+	af = ipaddr.ipadm_af;
+	if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
+		i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
+		status = i_ipadm_get_flags(iph, lifname, af, &flags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		if (inform) {
+			ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
+			return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
+		}
+		if (!(flags & IFF_DUPLICATE))
+			return (IPADM_SUCCESS);
+		status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
+	} else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
+		status = i_ipadm_op_dhcp(&ipaddr, DHCP_EXTEND, &dherr);
+		/*
+		 * Restart the dhcp address negotiation with server if no
+		 * address has been acquired yet.
+		 */
+		if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
+			ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
+			status = i_ipadm_op_dhcp(&ipaddr, DHCP_START, NULL);
+		}
+	} else {
+		status = IPADM_NOTSUP;
+	}
+	return (status);
+}
+
+/*
+ * This is called from ipadm_create_addr() to validate the address parameters.
+ * It does the following steps:
+ * 1. Validates the interface name.
+ * 2. Verifies that the interface is not an IPMP meta-interface or an
+ *	underlying interface.
+ * 3. In case of a persistent operation, verifies that the interface
+ *	is persistent. Returns error if interface is not enabled but
+ *	is in persistent config.
+ * 4. Verifies that the destination address is not set or the address type is
+ *	not DHCP or ADDRCONF when the interface is a loopback interface.
+ * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
+ *	has IFF_VRRP interface flag set.
+ */
+static ipadm_status_t
+i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
+    uint32_t flags)
+{
+	sa_family_t		af;
+	sa_family_t		other_af;
+	char			*ifname;
+	ipadm_status_t		status;
+	boolean_t		legacy = (iph->iph_flags & IPH_LEGACY);
+	boolean_t		islo, isvni;
+	uint64_t		ifflags = 0;
+	boolean_t		p_exists;
+	boolean_t		af_exists, other_af_exists, a_exists;
+
+	if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
+	    (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP))) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	if (ipaddr->ipadm_af == AF_UNSPEC)
+		return (IPADM_BAD_ADDR);
+
+	if (!legacy && ipaddr->ipadm_lifnum != 0)
+		return (IPADM_INVALID_ARG);
+
+	if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
+		return (IPADM_NOTSUP);
+
+	ifname = ipaddr->ipadm_ifname;
+
+	if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
+		return (IPADM_NOTSUP);
+
+	af = ipaddr->ipadm_af;
+	af_exists = ipadm_if_enabled(iph, ifname, af);
+	/*
+	 * For legacy case, interfaces are not implicitly plumbed. We need to
+	 * check if the interface exists in the active configuration.
+	 */
+	if (legacy && !af_exists)
+		return (IPADM_ENXIO);
+
+	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
+	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
+	/*
+	 * Check if one of the v4 or the v6 interfaces exists in the
+	 * active configuration. An interface is considered disabled only
+	 * if both v4 and v6 are not active.
+	 */
+	a_exists = (af_exists || other_af_exists);
+
+	/* Check if interface exists in the persistent configuration. */
+	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	if (!a_exists && p_exists)
+		return (IPADM_OP_DISABLE_OBJ);
+	if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
+		/*
+		 * If address has to be created persistently,
+		 * and the interface does not exist in the persistent
+		 * store but in active config, fail.
+		 */
+		return (IPADM_TEMPORARY_OBJ);
+	}
+	if (af_exists) {
+		status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+	}
+
+	/* Perform validation steps (4) and (5) */
+	islo = i_ipadm_is_loopback(ifname);
+	isvni = i_ipadm_is_vni(ifname);
+	switch (ipaddr->ipadm_atype) {
+	case IPADM_ADDR_STATIC:
+		if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
+			return (IPADM_INVALID_ARG);
+		/* Check for a valid src address */
+		if (!legacy && sockaddrunspec(&ipaddr->ipadm_static_addr))
+			return (IPADM_BAD_ADDR);
+		break;
+	case IPADM_ADDR_DHCP:
+		if (islo || (ifflags & IFF_VRRP))
+			return (IPADM_NOTSUP);
+		break;
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		if (islo || (ifflags & IFF_VRRP) ||
+		    i_ipadm_is_6to4(iph, ifname)) {
+			return (IPADM_NOTSUP);
+		}
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+ipadm_status_t
+i_ipadm_merge_prefixlen_from_nvl(nvlist_t *invl, nvlist_t *onvl,
+    const char *aobjname)
+{
+	nvpair_t	*nvp, *prefixnvp;
+	nvlist_t	*tnvl;
+	char		*aname;
+	int		err;
+
+	for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(invl, nvp)) {
+		if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
+		    nvlist_exists(tnvl, IPADM_NVP_PREFIXLEN) &&
+		    nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
+		    &aname) == 0 && strcmp(aname, aobjname) == 0) {
+			/* prefixlen exists for given address object */
+			(void) nvlist_lookup_nvpair(tnvl, IPADM_NVP_PREFIXLEN,
+			    &prefixnvp);
+			err = nvlist_add_nvpair(onvl, prefixnvp);
+			if (err == 0) {
+				err = nvlist_remove(invl, nvpair_name(nvp),
+				    nvpair_type(nvp));
+			}
+			return (ipadm_errno2status(err));
+		}
+	}
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Re-enables the address object `aobjname' based on the saved
+ * configuration for `aobjname'.
+ */
+ipadm_status_t
+ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
+{
+	nvlist_t	*addrnvl, *nvl;
+	nvpair_t	*nvp;
+	ipadm_status_t	status;
+	struct ipadm_addrobj_s ipaddr;
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* validate input */
+	if (flags & IPADM_OPT_PERSIST)
+		return (IPADM_NOTSUP);
+	if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
+	    IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* Retrieve the address object information. */
+	status = i_ipadm_get_addrobj(iph, &ipaddr);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
+		return (IPADM_ADDROBJ_EXISTS);
+
+	status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	assert(addrnvl != NULL);
+
+	for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(addrnvl, nvp)) {
+		if (nvpair_value_nvlist(nvp, &nvl) != 0)
+			continue;
+
+		if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
+		    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
+			status = i_ipadm_merge_prefixlen_from_nvl(addrnvl, nvl,
+			    aobjname);
+			if (status != IPADM_SUCCESS)
+				continue;
+		}
+		iph->iph_flags |= IPH_INIT;
+		status = i_ipadm_init_addrobj(iph, nvl);
+		iph->iph_flags &= ~IPH_INIT;
+		if (status != IPADM_SUCCESS)
+			break;
+	}
+
+	return (status);
+}
+
+/*
+ * Disables the address object in `aobjname' from the active configuration.
+ * Error code return values follow the model in ipadm_delete_addr().
+ */
+ipadm_status_t
+ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
+{
+	/* validate input */
+	if (flags & IPADM_OPT_PERSIST)
+		return (IPADM_NOTSUP);
+
+	return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_if.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,1534 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <errno.h>
+#include <sys/sockio.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <strings.h>
+#include <libdlpi.h>
+#include <libdllink.h>
+#include <libinetutil.h>
+#include <inet/ip.h>
+#include <limits.h>
+#include <zone.h>
+#include <ipadm_ndpd.h>
+#include "libipadm_impl.h"
+
+static ipadm_status_t	i_ipadm_slifname_arp(char *, uint64_t, int);
+static ipadm_status_t	i_ipadm_slifname(ipadm_handle_t, char *, char *,
+			    uint64_t, int, uint32_t);
+static ipadm_status_t	i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
+			    sa_family_t);
+static ipadm_status_t	i_ipadm_persist_if(ipadm_handle_t, const char *,
+			    sa_family_t);
+
+/*
+ * Returns B_FALSE if the interface in `ifname' has at least one address that is
+ * IFF_UP in the addresses in `ifa'.
+ */
+static boolean_t
+i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
+{
+	struct ifaddrs	*ifap;
+	char		cifname[LIFNAMSIZ];
+	char		*sep;
+
+	for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
+		(void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
+		if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
+			*sep = '\0';
+		/*
+		 * If this condition is true, there is at least one
+		 * address that is IFF_UP. So, we need to return B_FALSE.
+		 */
+		if (strcmp(cifname, ifname) == 0 &&
+		    (ifap->ifa_flags & IFF_UP)) {
+			return (B_FALSE);
+		}
+	}
+	/* We did not find any IFF_UP addresses. */
+	return (B_TRUE);
+}
+
+/*
+ * Retrieves the information for the interface `ifname' from active
+ * config if `ifname' is specified and returns the result in the list `if_info'.
+ * Otherwise, it retrieves the information for all the interfaces in
+ * the active config and returns the result in the list `if_info'.
+ */
+static ipadm_status_t
+i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_if_info_t **if_info, int64_t lifc_flags)
+{
+	struct lifreq	*buf;
+	struct lifreq	*lifrp;
+	struct lifreq	lifrl;
+	ipadm_if_info_t	*last = NULL;
+	ipadm_if_info_t	*ifp;
+	int		s;
+	int		n;
+	int		numifs;
+	ipadm_status_t	status;
+
+	*if_info = NULL;
+	/*
+	 * Get information for all interfaces.
+	 */
+	if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0)
+		return (ipadm_errno2status(errno));
+
+	lifrp = buf;
+	for (n = 0; n < numifs; n++, lifrp++) {
+		/* Skip interfaces with logical num != 0 */
+		if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
+			continue;
+		/*
+		 * Skip the current interface if a specific `ifname' has
+		 * been requested and current interface does not match
+		 * `ifname'.
+		 */
+		if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
+			continue;
+		/*
+		 * Check if the interface already exists in our list.
+		 * If it already exists, we need to update its flags.
+		 */
+		for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
+			if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
+				break;
+		}
+		if (ifp == NULL) {
+			ifp = calloc(1, sizeof (ipadm_if_info_t));
+			if (ifp == NULL) {
+				status = ipadm_errno2status(errno);
+				goto fail;
+			}
+			(void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
+			    sizeof (ifp->ifi_name));
+			/* Update the `ifi_next' pointer for this new node */
+			if (*if_info == NULL)
+				*if_info = ifp;
+			else
+				last->ifi_next = ifp;
+			last = ifp;
+		}
+
+		/*
+		 * Retrieve the flags for the interface by doing a
+		 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
+		 */
+		(void) strlcpy(lifrl.lifr_name,
+		    lifrp->lifr_name, sizeof (lifrl.lifr_name));
+		s = (lifrp->lifr_addr.ss_family == AF_INET) ?
+		    iph->iph_sock : iph->iph_sock6;
+		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
+			continue;
+		if (lifrl.lifr_flags & IFF_BROADCAST)
+			ifp->ifi_cflags |= IFIF_BROADCAST;
+		if (lifrl.lifr_flags & IFF_MULTICAST)
+			ifp->ifi_cflags |= IFIF_MULTICAST;
+		if (lifrl.lifr_flags & IFF_POINTOPOINT)
+			ifp->ifi_cflags |= IFIF_POINTOPOINT;
+		if (lifrl.lifr_flags & IFF_VIRTUAL)
+			ifp->ifi_cflags |= IFIF_VIRTUAL;
+		if (lifrl.lifr_flags & IFF_IPMP)
+			ifp->ifi_cflags |= IFIF_IPMP;
+		if (lifrl.lifr_flags & IFF_STANDBY)
+			ifp->ifi_cflags |= IFIF_STANDBY;
+		if (lifrl.lifr_flags & IFF_INACTIVE)
+			ifp->ifi_cflags |= IFIF_INACTIVE;
+		if (lifrl.lifr_flags & IFF_VRRP)
+			ifp->ifi_cflags |= IFIF_VRRP;
+		if (lifrl.lifr_flags & IFF_NOACCEPT)
+			ifp->ifi_cflags |= IFIF_NOACCEPT;
+		if (lifrl.lifr_flags & IFF_IPV4)
+			ifp->ifi_cflags |= IFIF_IPV4;
+		if (lifrl.lifr_flags & IFF_IPV6)
+			ifp->ifi_cflags |= IFIF_IPV6;
+	}
+	free(buf);
+	return (IPADM_SUCCESS);
+fail:
+	free(buf);
+	ipadm_free_if_info(*if_info);
+	*if_info = NULL;
+	return (status);
+}
+
+/*
+ * Returns the interface information for `ifname' in `if_info' from persistent
+ * config if `ifname' is non-null. Otherwise, it returns all the interfaces
+ * from persistent config in `if_info'.
+ */
+static ipadm_status_t
+i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_if_info_t **if_info)
+{
+	ipadm_status_t		status = IPADM_SUCCESS;
+	ipmgmt_getif_arg_t	getif;
+	ipmgmt_getif_rval_t	*rvalp;
+	ipadm_if_info_t		*ifp, *curr, *prev = NULL;
+	int			i = 0, err = 0;
+
+	bzero(&getif, sizeof (getif));
+	if (ifname != NULL)
+		(void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
+	getif.ia_cmd = IPMGMT_CMD_GETIF;
+
+	*if_info = NULL;
+
+	if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
+		return (ipadm_errno2status(errno));
+	err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
+	    sizeof (*rvalp), B_TRUE);
+	if (err == ENOENT) {
+		free(rvalp);
+		if (ifname != NULL)
+			return (ipadm_errno2status(err));
+		return (IPADM_SUCCESS);
+	} else if (err != 0) {
+		free(rvalp);
+		return (ipadm_errno2status(err));
+	}
+
+	ifp = rvalp->ir_ifinfo;
+	for (i = 0; i < rvalp->ir_ifcnt; i++) {
+		ifp = rvalp->ir_ifinfo + i;
+		if ((curr = malloc(sizeof (*curr))) == NULL) {
+			status = ipadm_errno2status(errno);
+			ipadm_free_if_info(prev);
+			break;
+		}
+		(void) bcopy(ifp, curr, sizeof (*curr));
+		curr->ifi_next = prev;
+		prev = curr;
+	}
+	*if_info = curr;
+	free(rvalp);
+	return (status);
+}
+
+/*
+ * Collects information for `ifname' if one is specified from both
+ * active and persistent config in `if_info'. If no `ifname' is specified,
+ * this returns all the interfaces in active and persistent config in
+ * `if_info'.
+ */
+ipadm_status_t
+i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_if_info_t **if_info, int64_t lifc_flags)
+{
+	ipadm_status_t	status;
+	ipadm_if_info_t	*aifinfo = NULL;
+	ipadm_if_info_t	*pifinfo = NULL;
+	ipadm_if_info_t	*aifp;
+	ipadm_if_info_t	*pifp;
+	ipadm_if_info_t	*last = NULL;
+	struct ifaddrs	*ifa;
+	struct ifaddrs	*ifap;
+
+	/*
+	 * Retrive the information for the requested `ifname' or all
+	 * interfaces from active configuration.
+	 */
+retry:
+	status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	/* Get the interface state for each interface in `aifinfo'. */
+	if (aifinfo != NULL) {
+		/* We need all addresses to get the interface state */
+		if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY|
+		    LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) {
+			status = ipadm_errno2status(errno);
+			goto fail;
+		}
+		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
+			/*
+			 * Find the `ifaddrs' structure from `ifa'
+			 * for this interface. We need the IFF_* flags
+			 * to find the interface state.
+			 */
+			for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
+				if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0)
+					break;
+			}
+			if (ifap == NULL) {
+				/*
+				 * The interface might have been removed
+				 * from kernel. Retry getting all the active
+				 * interfaces.
+				 */
+				freeifaddrs(ifa);
+				ipadm_free_if_info(aifinfo);
+				aifinfo = NULL;
+				goto retry;
+			}
+			if (!(ifap->ifa_flags & IFF_RUNNING) ||
+			    (ifap->ifa_flags & IFF_FAILED))
+				aifp->ifi_state = IFIS_FAILED;
+			else if (ifap->ifa_flags & IFF_OFFLINE)
+				aifp->ifi_state = IFIS_OFFLINE;
+			else if (i_ipadm_is_if_down(aifp->ifi_name, ifa))
+				aifp->ifi_state = IFIS_DOWN;
+			else
+				aifp->ifi_state = IFIS_OK;
+			if (aifp->ifi_next == NULL)
+				last = aifp;
+		}
+		freeifaddrs(ifa);
+	}
+	/*
+	 * Get the persistent interface information in `pifinfo'.
+	 */
+	status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
+	if (status == IPADM_NOTFOUND) {
+		*if_info = aifinfo;
+		return (IPADM_SUCCESS);
+	}
+	if (status != IPADM_SUCCESS)
+		goto fail;
+	/*
+	 * If a persistent interface is also found in `aifinfo', update
+	 * its entry in `aifinfo' with the persistent information from
+	 * `pifinfo'. If an interface is found in `pifinfo', but not in
+	 * `aifinfo', it means that this interface was disabled. We should
+	 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
+	 */
+	for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
+		for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
+			if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
+				aifp->ifi_pflags = pifp->ifi_pflags;
+				break;
+			}
+		}
+		if (aifp == NULL) {
+			aifp = malloc(sizeof (ipadm_if_info_t));
+			if (aifp == NULL) {
+				status = ipadm_errno2status(errno);
+				goto fail;
+			}
+			*aifp = *pifp;
+			aifp->ifi_next = NULL;
+			aifp->ifi_state = IFIS_DISABLED;
+			if (last != NULL)
+				last->ifi_next = aifp;
+			else
+				aifinfo = aifp;
+			last = aifp;
+		}
+	}
+	*if_info = aifinfo;
+	ipadm_free_if_info(pifinfo);
+	return (IPADM_SUCCESS);
+fail:
+	*if_info = NULL;
+	ipadm_free_if_info(aifinfo);
+	ipadm_free_if_info(pifinfo);
+	return (status);
+}
+
+int
+i_ipadm_get_lnum(const char *ifname)
+{
+	char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
+
+	if (num == NULL)
+		return (0);
+
+	return (atoi(++num));
+}
+
+/*
+ * Sets the output argument `exists' to true or false based on whether
+ * any persistent configuration is available for `ifname' and returns
+ * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
+ * `exists' is unmodified and an error status is returned.
+ */
+ipadm_status_t
+i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    boolean_t *exists)
+{
+	ipadm_if_info_t	*ifinfo;
+	ipadm_status_t	status;
+
+	status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
+	if (status == IPADM_SUCCESS) {
+		*exists = ((af == AF_INET &&
+		    (ifinfo->ifi_pflags & IFIF_IPV4)) ||
+		    (af == AF_INET6 &&
+		    (ifinfo->ifi_pflags & IFIF_IPV6)));
+		free(ifinfo);
+	} else if (status == IPADM_NOTFOUND) {
+		status = IPADM_SUCCESS;
+		*exists = B_FALSE;
+	}
+	return (status);
+}
+
+/*
+ * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
+ * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
+ * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
+ * the bottom of the stream for tunneling interfaces.
+ */
+ipadm_status_t
+ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
+{
+	int err;
+
+	if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
+		return (ipadm_errno2status(errno));
+
+	/*
+	 * Pop off all undesired modules (note that the user may have
+	 * configured autopush to add modules above udp), and push the
+	 * arp module onto the resulting stream. This is used to make
+	 * IP+ARP be able to atomically track the muxid for the I_PLINKed
+	 * STREAMS, thus it isn't related to ARP running the ARP protocol.
+	 */
+	while (ioctl(*fd, I_POP, 0) != -1)
+		;
+	if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1)
+		return (IPADM_SUCCESS);
+	err = errno;
+	(void) close(*fd);
+
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
+ * underlying interface in an ipmp group G is plumbed for an address family,
+ * but the meta-interface for the other address family `af' does not exist
+ * yet for the group G. If `af' is IPv6, we need to bring up the
+ * link-local address.
+ */
+static ipadm_status_t
+i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af,
+    const char *grname, uint32_t ipadm_flags)
+{
+	ipadm_status_t	status;
+	struct lifreq	lifr;
+	int		sock;
+	int		err;
+
+	assert(ipadm_flags & IPADM_OPT_IPMP);
+
+	/* Create the ipmp underlying interface */
+	status = i_ipadm_create_if(iph, ifname, af, ipadm_flags);
+	if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
+		return (status);
+
+	/*
+	 * To preserve backward-compatibility, always bring up the link-local
+	 * address for implicitly-created IPv6 IPMP interfaces.
+	 */
+	if (af == AF_INET6)
+		(void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0);
+
+	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+	/*
+	 * If the caller requested a different group name, issue a
+	 * SIOCSLIFGROUPNAME on the new IPMP interface.
+	 */
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (strcmp(lifr.lifr_name, grname) != 0) {
+		(void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
+		if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) {
+			err = errno;
+			/* Remove the interface we created. */
+			if (status == IPADM_SUCCESS) {
+				(void) i_ipadm_delete_if(iph, ifname, af,
+				    ipadm_flags);
+			}
+			return (ipadm_errno2status(err));
+		}
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
+ * family.  If so, create a matching IPMP group for address family `af'.
+ */
+static ipadm_status_t
+i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af)
+{
+	lifgroupinfo_t	lifgr;
+	ipadm_status_t	status = IPADM_SUCCESS;
+	struct lifreq	lifr;
+	int 		other_af_sock;
+
+	assert(af == AF_INET || af == AF_INET6);
+
+	other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock);
+
+	/*
+	 * iph is the handle for the interface that we are trying to plumb.
+	 * other_af_sock is the socket for the "other" address family.
+	 */
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0)
+		return (IPADM_SUCCESS);
+
+	(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
+	if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0)
+		return (IPADM_SUCCESS);
+
+	/*
+	 * If `ifname' *is* the IPMP group interface, or if the relevant
+	 * address family is already configured, then there's nothing to do.
+	 */
+	if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
+	    (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) {
+		return (IPADM_SUCCESS);
+	}
+
+	status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af,
+	    lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP);
+	return (status);
+}
+
+/*
+ * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
+ */
+static ipadm_status_t
+i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd)
+{
+	struct lifreq	lifr;
+	ifspec_t	ifsp;
+
+	bzero(&lifr, sizeof (lifr));
+	(void) ifparse_ifspec(ifname, &ifsp);
+	lifr.lifr_ppa = ifsp.ifsp_ppa;
+	lifr.lifr_flags = flags;
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	/*
+	 * Tell ARP the name and unit number for this interface.
+	 * Note that arp has no support for transparent ioctls.
+	 */
+	if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr,
+	    sizeof (lifr)) == -1) {
+		return (ipadm_errno2status(errno));
+	}
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
+ * `ipadm_flags', then a ppa will be generated. `newif' will be updated
+ * with the generated ppa.
+ */
+static ipadm_status_t
+i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags,
+    int fd, uint32_t ipadm_flags)
+{
+	struct lifreq	lifr;
+	ipadm_status_t	status = IPADM_SUCCESS;
+	int		err = 0;
+	sa_family_t	af;
+	int		ppa;
+	ifspec_t	ifsp;
+	boolean_t	valid_if;
+
+	bzero(&lifr, sizeof (lifr));
+	if (ipadm_flags & IPADM_OPT_GENPPA) {
+		/*
+		 * We'd like to just set lifr_ppa to UINT_MAX and have the
+		 * kernel pick a PPA.  Unfortunately, that would mishandle
+		 * two cases:
+		 *
+		 *	1. If the PPA is available but the groupname is taken
+		 *	   (e.g., the "ipmp2" IP interface name is available
+		 *	   but the "ipmp2" groupname is taken) then the
+		 *	   auto-assignment by the kernel will fail.
+		 *
+		 *	2. If we're creating (e.g.) an IPv6-only IPMP
+		 *	   interface, and there's already an IPv4-only IPMP
+		 *	   interface, the kernel will allow us to accidentally
+		 *	   reuse the IPv6 IPMP interface name (since
+		 *	   SIOCSLIFNAME uniqueness is per-interface-type).
+		 *	   This will cause administrative confusion.
+		 *
+		 * Thus, we instead take a brute-force approach of checking
+		 * whether the IPv4 or IPv6 name is already in-use before
+		 * attempting the SIOCSLIFNAME.  As per (1) above, the
+		 * SIOCSLIFNAME may still fail, in which case we just proceed
+		 * to the next one.  If this approach becomes too slow, we
+		 * can add a new SIOC* to handle this case in the kernel.
+		 */
+		for (ppa = 0; ppa < UINT_MAX; ppa++) {
+			(void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
+			    ifname, ppa);
+
+			if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 ||
+			    errno != ENXIO)
+				continue;
+
+			if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 ||
+			    errno != ENXIO)
+				continue;
+
+			lifr.lifr_ppa = ppa;
+			lifr.lifr_flags = flags;
+
+			err = ioctl(fd, SIOCSLIFNAME, &lifr);
+			if (err != -1 || errno != EEXIST)
+				break;
+		}
+		if (err == -1) {
+			status = ipadm_errno2status(errno);
+		} else {
+			/*
+			 * PPA has been successfully established.
+			 * Update `newif' with the ppa.
+			 */
+			assert(newif != NULL);
+			if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname,
+			    ppa) >= LIFNAMSIZ)
+				return (IPADM_INVALID_ARG);
+		}
+	} else {
+		/* We should have already validated the interface name. */
+		valid_if = ifparse_ifspec(ifname, &ifsp);
+		assert(valid_if);
+
+		/*
+		 * Before we call SIOCSLIFNAME, ensure that the IPMP group
+		 * interface for this address family exists.  Otherwise, the
+		 * kernel will kick the interface out of the group when we do
+		 * the SIOCSLIFNAME.
+		 *
+		 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
+		 * If we're now plumbing bge0 for IPv6, but the IPMP group
+		 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
+		 * will kick bge0 out of group "a", which is undesired.
+		 */
+		if (flags & IFF_IPV4)
+			af = AF_INET;
+		else
+			af = AF_INET6;
+		status = i_ipadm_create_ipmp_peer(iph, ifname, af);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		lifr.lifr_ppa = ifsp.ifsp_ppa;
+		lifr.lifr_flags = flags;
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+		if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
+			status = ipadm_errno2status(errno);
+	}
+
+	return (status);
+}
+
+/*
+ * Plumbs the interface `ifname' for the address family `af'. It also persists
+ * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
+ */
+ipadm_status_t
+i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
+    uint32_t ipadm_flags)
+{
+	int		ip_muxid;
+	int		mux_fd = -1, ip_fd, arp_fd;
+	char		*udp_dev_name;
+	dlpi_handle_t	dh_arp = NULL, dh_ip;
+	uint64_t	ifflags;
+	struct lifreq	lifr;
+	uint_t		dlpi_flags;
+	ipadm_status_t	status = IPADM_SUCCESS;
+	char		*linkname;
+	boolean_t	legacy = (iph->iph_flags & IPH_LEGACY);
+	zoneid_t	zoneid;
+	char		newif[LIFNAMSIZ];
+	char		lifname[LIFNAMSIZ];
+	datalink_id_t	linkid;
+	int		sock;
+	boolean_t	islo;
+	boolean_t	is_persistent =
+	    ((ipadm_flags & IPADM_OPT_PERSIST) != 0);
+	uint32_t	dlflags;
+	dladm_status_t	dlstatus;
+
+	if (iph->iph_dlh != NULL) {
+		dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid,
+		    &dlflags, NULL, NULL);
+	}
+	/*
+	 * If we're in the global zone and we're plumbing a datalink, make
+	 * sure that the datalink is not assigned to a non-global zone.  Note
+	 * that the non-global zones don't need this check, because zoneadm
+	 * has taken care of this when the zones boot.
+	 */
+	if (getzoneid() == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
+		zoneid = ALL_ZONES;
+		if (zone_check_datalink(&zoneid, linkid) == 0) {
+			/* interface is in use by a non-global zone. */
+			return (IPADM_IF_INUSE);
+		}
+	}
+
+	/* loopback interfaces are just added as logical interface */
+	bzero(&lifr, sizeof (lifr));
+	islo = i_ipadm_is_loopback(ifname);
+	if (islo || i_ipadm_get_lnum(ifname) != 0) {
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+		if (af == AF_INET)
+			sock = iph->iph_sock;
+		else
+			sock = iph->iph_sock6;
+		if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
+			return (IPADM_IF_EXISTS);
+		if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+
+		/*
+		 * By default, kernel configures 127.0.0.1 on the loopback
+		 * interface. Replace this with 0.0.0.0 to be consistent
+		 * with interface creation on other physical interfaces.
+		 */
+		if (islo && !legacy) {
+			bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
+			lifr.lifr_addr.ss_family = af;
+			if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
+				return (ipadm_errno2status(errno));
+			if (is_persistent) {
+				status = i_ipadm_persist_if(iph, ifname, af);
+				if (status != IPADM_SUCCESS) {
+					(void) i_ipadm_delete_if(iph, ifname,
+					    af, IPADM_OPT_ACTIVE);
+				}
+			}
+		}
+		return (status);
+	}
+
+	dlpi_flags = DLPI_NOATTACH;
+
+	/*
+	 * If IPADM_OPT_IPMP is specified, then this is a request
+	 * to create an IPMP interface atop /dev/ipmpstub0.  (We can't simply
+	 * pass "ipmpstub0" as devname since an admin *could* have a normal
+	 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
+	 */
+	if (ipadm_flags & IPADM_OPT_IPMP) {
+		dlpi_flags |= DLPI_DEVONLY;
+		linkname = "ipmpstub0";
+	} else {
+		/*
+		 * Verify that the user is not creating a persistent
+		 * IP interface on a non-persistent data-link.
+		 */
+		if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK &&
+		    is_persistent && !(dlflags & DLADM_OPT_PERSIST)) {
+				return (IPADM_TEMPORARY_OBJ);
+		}
+		linkname = ifname;
+	}
+
+	/*
+	 * We use DLPI_NOATTACH because the ip module will do the attach
+	 * itself for DLPI style-2 devices.
+	 */
+	if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS)
+		return (IPADM_DLPI_FAILURE);
+	ip_fd = dlpi_fd(dh_ip);
+	if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) {
+		status = ipadm_errno2status(errno);
+		goto done;
+	}
+
+	/*
+	 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
+	 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
+	 */
+	ifflags = 0;
+
+	/* Set the name string and the IFF_IPV* flag */
+	if (af == AF_INET) {
+		ifflags = IFF_IPV4;
+	} else {
+		ifflags = IFF_IPV6;
+		/*
+		 * With the legacy method, the link-local address should be
+		 * configured as part of the interface plumb, using the default
+		 * token. If IPH_LEGACY is not specified, we want to set :: as
+		 * the address and require the admin to explicitly call
+		 * ipadm_create_addr() with the address object type set to
+		 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
+		 * as well as the autoconfigured addresses.
+		 */
+		if (!legacy && !i_ipadm_is_6to4(iph, ifname))
+			ifflags |= IFF_NOLINKLOCAL;
+	}
+	(void) strlcpy(newif, ifname, sizeof (newif));
+	status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd,
+	    ipadm_flags);
+	if (status != IPADM_SUCCESS)
+		goto done;
+
+	/* Get the full set of existing flags for this stream */
+	status = i_ipadm_get_flags(iph, newif, af, &ifflags);
+	if (status != IPADM_SUCCESS)
+		goto done;
+
+	udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME);
+	status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
+	if (status != IPADM_SUCCESS)
+		goto done;
+
+	/* Check if arp is not needed */
+	if (ifflags & (IFF_NOARP|IFF_IPV6)) {
+		/*
+		 * PLINK the interface stream so that the application can exit
+		 * without tearing down the stream.
+		 */
+		if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
+			status = ipadm_errno2status(errno);
+		goto done;
+	}
+
+	/*
+	 * This interface does use ARP, so set up a separate stream
+	 * from the interface to ARP.
+	 *
+	 * We use DLPI_NOATTACH because the arp module will do the attach
+	 * itself for DLPI style-2 devices.
+	 */
+	if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) {
+		status = IPADM_DLPI_FAILURE;
+		goto done;
+	}
+
+	arp_fd = dlpi_fd(dh_arp);
+	if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) {
+		status = ipadm_errno2status(errno);
+		goto done;
+	}
+
+	status = i_ipadm_slifname_arp(newif, ifflags, arp_fd);
+	if (status != IPADM_SUCCESS)
+		goto done;
+	/*
+	 * PLINK the IP and ARP streams so that ifconfig can exit
+	 * without tearing down the stream.
+	 */
+	if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
+		status = ipadm_errno2status(errno);
+		goto done;
+	}
+
+	if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) {
+		status = ipadm_errno2status(errno);
+		(void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
+	}
+
+done:
+	dlpi_close(dh_ip);
+	if (dh_arp != NULL)
+		dlpi_close(dh_arp);
+
+	if (mux_fd != -1)
+		(void) close(mux_fd);
+
+	if (status == IPADM_SUCCESS) {
+		/* copy back new ifname */
+		(void) strlcpy(ifname, newif, LIFNAMSIZ);
+		/*
+		 * If it is a 6to4 tunnel, create a default
+		 * addrobj name for the default address on the 0'th
+		 * logical interface and set IFF_UP in the interface flags.
+		 */
+		if (i_ipadm_is_6to4(iph, ifname)) {
+			struct ipadm_addrobj_s addr;
+
+			i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC);
+			addr.ipadm_af = af;
+			status = i_ipadm_lookupadd_addrobj(iph, &addr);
+			if (status != IPADM_SUCCESS)
+				return (status);
+			status = ipadm_add_aobjname(iph, ifname,
+			    af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0);
+			if (status != IPADM_SUCCESS)
+				return (status);
+			addr.ipadm_lifnum = 0;
+			i_ipadm_addrobj2lifname(&addr, lifname,
+			    sizeof (lifname));
+			status = i_ipadm_set_flags(iph, lifname, af,
+			    IFF_UP, 0);
+			if (status != IPADM_SUCCESS)
+				return (status);
+		} else {
+			/*
+			 * Prevent static IPv6 addresses from triggering
+			 * autoconf. This does not have to be done for
+			 * 6to4 tunnel interfaces, since in.ndpd will
+			 * not autoconfigure those interfaces.
+			 */
+			if (af == AF_INET6 && !legacy)
+				(void) i_ipadm_disable_autoconf(newif);
+		}
+
+		/*
+		 * If IPADM_OPT_PERSIST was set in flags, store the
+		 * interface in persistent DB.
+		 */
+		if (is_persistent) {
+			status = i_ipadm_persist_if(iph, newif, af);
+			if (status != IPADM_SUCCESS) {
+				(void) i_ipadm_delete_if(iph, newif, af,
+				    IPADM_OPT_ACTIVE);
+			}
+		}
+	}
+	if (status == IPADM_EXISTS)
+		status = IPADM_IF_EXISTS;
+	return (status);
+}
+
+/*
+ * Unplumbs the interface in `ifname' of family `af'.
+ */
+ipadm_status_t
+i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
+{
+	int		ip_muxid, arp_muxid;
+	int		mux_fd = -1;
+	int		muxid_fd = -1;
+	char		*udp_dev_name;
+	uint64_t	flags;
+	boolean_t	changed_arp_muxid = B_FALSE;
+	int		save_errno;
+	struct lifreq	lifr;
+	ipadm_status_t	ret = IPADM_SUCCESS;
+	int		sock;
+	lifgroupinfo_t	lifgr;
+	ifaddrlistx_t	*ifaddrs, *ifaddrp;
+	boolean_t	v6 = (af == AF_INET6);
+
+	/* Just do SIOCLIFREMOVEIF on loopback interfaces */
+	bzero(&lifr, sizeof (lifr));
+	if (i_ipadm_is_loopback(ifname) ||
+	    (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) {
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+		if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6,
+		    SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
+			return (ipadm_errno2status(errno));
+		}
+		return (IPADM_SUCCESS);
+	}
+
+	/*
+	 * We used /dev/udp or udp6 to set up the mux. So we have to use
+	 * the same now for PUNLINK also.
+	 */
+	if (v6) {
+		udp_dev_name = UDP6_DEV_NAME;
+		sock = iph->iph_sock6;
+	} else {
+		udp_dev_name = UDP_DEV_NAME;
+		sock = iph->iph_sock;
+	}
+	if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) {
+		ret = ipadm_errno2status(errno);
+		goto done;
+	}
+	ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
+	if (ret != IPADM_SUCCESS)
+		goto done;
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
+		ret = ipadm_errno2status(errno);
+		goto done;
+	}
+	flags = lifr.lifr_flags;
+again:
+	if (flags & IFF_IPMP) {
+		/*
+		 * There are two reasons the I_PUNLINK can fail with EBUSY:
+		 * (1) if IP interfaces are in the group, or (2) if IPMP data
+		 * addresses are administratively up.  For case (1), we fail
+		 * here with a specific error message.  For case (2), we bring
+		 * down the addresses prior to doing the I_PUNLINK.  If the
+		 * I_PUNLINK still fails with EBUSY then the configuration
+		 * must have changed after our checks, in which case we branch
+		 * back up to `again' and rerun this logic.  The net effect is
+		 * that unplumbing an IPMP interface will only fail with EBUSY
+		 * if IP interfaces are in the group.
+		 */
+		if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) {
+			ret = ipadm_errno2status(errno);
+			goto done;
+		}
+		(void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
+		    LIFGRNAMSIZ);
+		if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) {
+			ret = ipadm_errno2status(errno);
+			goto done;
+		}
+		if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
+			ret = IPADM_GRP_NOTEMPTY;
+			goto done;
+		}
+
+		/*
+		 * The kernel will fail the I_PUNLINK if the IPMP interface
+		 * has administratively up addresses; bring them down.
+		 */
+		if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE,
+		    0, &ifaddrs) == -1) {
+			ret = ipadm_errno2status(errno);
+			goto done;
+		}
+		ifaddrp = ifaddrs;
+		for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
+			int sock = (ifaddrp->ia_flags & IFF_IPV4) ?
+			    iph->iph_sock : iph->iph_sock6;
+			struct lifreq lifrl;
+
+			if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
+			    (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
+				continue;
+
+			bzero(&lifrl, sizeof (lifrl));
+			(void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name,
+			    sizeof (lifrl.lifr_name));
+			if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) {
+				ret = ipadm_errno2status(errno);
+				ifaddrlistx_free(ifaddrs);
+				goto done;
+			}
+			if (lifrl.lifr_flags & IFF_UP) {
+				ret = i_ipadm_set_flags(iph, lifrl.lifr_name,
+				    ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET :
+				    AF_INET6), 0, IFF_UP);
+				if (ret != IPADM_SUCCESS) {
+					ifaddrlistx_free(ifaddrs);
+					goto done;
+				}
+			} else if (lifrl.lifr_flags & IFF_DUPLICATE) {
+				if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 ||
+				    ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) {
+					ret = ipadm_errno2status(errno);
+					ifaddrlistx_free(ifaddrs);
+					goto done;
+				}
+			}
+		}
+		ifaddrlistx_free(ifaddrs);
+	}
+
+	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
+		ret = ipadm_errno2status(errno);
+		goto done;
+	}
+	arp_muxid = lifr.lifr_arp_muxid;
+	ip_muxid = lifr.lifr_ip_muxid;
+
+	/*
+	 * We don't have a good way of knowing whether the arp stream is
+	 * plumbed. We can't rely on IFF_NOARP because someone could
+	 * have turned it off later using "ifconfig xxx -arp".
+	 */
+	if (arp_muxid != 0) {
+		if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
+			/*
+			 * See the comment before the SIOCGLIFGROUPNAME call.
+			 */
+			if (errno == EBUSY && (flags & IFF_IPMP))
+				goto again;
+
+			if ((errno == EINVAL) &&
+			    (flags & (IFF_NOARP | IFF_IPV6))) {
+				/*
+				 * Some plumbing utilities set the muxid to
+				 * -1 or some invalid value to signify that
+				 * there is no arp stream. Set the muxid to 0
+				 * before trying to unplumb the IP stream.
+				 * IP does not allow the IP stream to be
+				 * unplumbed if it sees a non-null arp muxid,
+				 * for consistency of IP-ARP streams.
+				 */
+				lifr.lifr_arp_muxid = 0;
+				(void) ioctl(muxid_fd, SIOCSLIFMUXID,
+				    (caddr_t)&lifr);
+				changed_arp_muxid = B_TRUE;
+			}
+			/*
+			 * In case of any other error, we continue with
+			 * the unplumb.
+			 */
+		}
+	}
+
+	if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
+		if (changed_arp_muxid) {
+			/*
+			 * Some error occurred, and we need to restore
+			 * everything back to what it was.
+			 */
+			save_errno = errno;
+			lifr.lifr_arp_muxid = arp_muxid;
+			lifr.lifr_ip_muxid = ip_muxid;
+			(void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
+			errno = save_errno;
+		}
+		/*
+		 * See the comment before the SIOCGLIFGROUPNAME call.
+		 */
+		if (errno == EBUSY && (flags & IFF_IPMP))
+			goto again;
+
+		ret = ipadm_errno2status(errno);
+	}
+done:
+	if (muxid_fd != -1)
+		(void) close(muxid_fd);
+	if (mux_fd != -1)
+		(void) close(mux_fd);
+
+	if (af == AF_INET6 && ret == IPADM_SUCCESS) {
+		/*
+		 * in.ndpd maintains the phyints in its memory even after
+		 * the interface is plumbed, so that it can be reused when
+		 * the interface gets plumbed again. The default behavior
+		 * of in.ndpd is to start autoconfiguration for an interface
+		 * that gets plumbed. We need to send the
+		 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
+		 * default behavior on replumb.
+		 */
+		(void) i_ipadm_enable_autoconf(ifname);
+	}
+	return (ret);
+}
+
+/*
+ * Saves the given interface name `ifname' with address family `af' in
+ * persistent DB.
+ */
+static ipadm_status_t
+i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
+{
+	ipmgmt_if_arg_t		ifarg;
+	int			err;
+
+	(void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
+	ifarg.ia_family = af;
+	ifarg.ia_cmd = IPMGMT_CMD_SETIF;
+	ifarg.ia_flags = IPMGMT_PERSIST;
+	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
+ * is set in `ipadm_flags', it is also removed from persistent configuration.
+ */
+ipadm_status_t
+i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    uint32_t ipadm_flags)
+{
+	ipadm_status_t		ret = IPADM_SUCCESS;
+	ipadm_status_t		db_status;
+	char			tmp_ifname[LIFNAMSIZ];
+	char			*cp;
+	struct ipadm_addrobj_s	ipaddr;
+	boolean_t		is_persistent =
+	    (ipadm_flags & IPADM_OPT_PERSIST);
+
+	ret = i_ipadm_unplumb_if(iph, ifname, af);
+	if (ret != IPADM_SUCCESS)
+		goto done;
+
+	cp = strrchr(ifname, IPADM_LOGICAL_SEP);
+	if (cp != NULL) {
+		assert(iph->iph_flags & IPH_LEGACY);
+		/*
+		 * This is a non-zero logical interface.
+		 * Find the addrobj and remove it from the daemon's memory.
+		 */
+		(void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname));
+		tmp_ifname[cp - ifname] = '\0';
+		*cp++ = '\0';
+		ipaddr.ipadm_lifnum = atoi(cp);
+		(void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname,
+		    sizeof (ipaddr.ipadm_ifname));
+		ipaddr.ipadm_af = af;
+		ret = i_ipadm_get_lif2addrobj(iph, &ipaddr);
+		if (ret == IPADM_SUCCESS) {
+			ret = i_ipadm_delete_addrobj(iph, &ipaddr,
+			    IPADM_OPT_ACTIVE);
+		} else if (ret == IPADM_NOTFOUND) {
+			ret = IPADM_SUCCESS;
+		}
+		return (ret);
+	}
+done:
+	/*
+	 * Even if interface does not exist, remove all its addresses and
+	 * properties from the persistent store. If interface does not
+	 * exist both in kernel and the persistent store, return IPADM_ENXIO.
+	 */
+	if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) {
+		db_status = i_ipadm_delete_ifobj(iph, ifname, af,
+		    is_persistent);
+		if (db_status == IPADM_SUCCESS)
+			ret = IPADM_SUCCESS;
+	}
+
+	return (ret);
+}
+
+/*
+ * Resets all addresses on interface `ifname' with address family `af'
+ * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
+ * and address objects of `ifname' for `af' are also removed from the
+ * persistent DB.
+ */
+ipadm_status_t
+i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    boolean_t is_persistent)
+{
+	ipmgmt_if_arg_t		ifarg;
+	int			err;
+
+	ifarg.ia_cmd = IPMGMT_CMD_RESETIF;
+	ifarg.ia_flags = IPMGMT_ACTIVE;
+	if (is_persistent)
+		ifarg.ia_flags |= IPMGMT_PERSIST;
+	ifarg.ia_family = af;
+	(void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ);
+
+	err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Create the interface by plumbing it for IP.
+ * This function will check if there is saved configuration information
+ * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
+ * for `ifname' is taken.
+ */
+ipadm_status_t
+i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
+    uint32_t ipadm_flags)
+{
+	ipadm_status_t	status;
+	boolean_t	p_exists;
+	sa_family_t	other_af;
+
+	/*
+	 * Return error, if the interface already exists in either the active
+	 * or the persistent configuration.
+	 */
+	if (ipadm_if_enabled(iph, ifname, af))
+		return (IPADM_IF_EXISTS);
+
+	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
+	if (p_exists) {
+		if (!ipadm_if_enabled(iph, ifname, other_af))
+			return (IPADM_OP_DISABLE_OBJ);
+		else
+			ipadm_flags &= ~IPADM_OPT_PERSIST;
+	}
+
+	return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
+}
+
+/*
+ * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
+ * default, unless a value in `af' is specified. The interface may be plumbed
+ * only if there is no previously saved persistent configuration information
+ * for the interface (in which case the ipadm_enable_if() function must
+ * be used to enable the interface).
+ *
+ * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
+ * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
+ * or appropriate ipadm_status_t corresponding to the errno.
+ *
+ * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
+ * be over-written with the actual interface name when a PPA has to be
+ * internally generated by the library.
+ */
+ipadm_status_t
+ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
+    uint32_t flags)
+{
+	ipadm_status_t	status;
+	boolean_t	created_v4 = B_FALSE;
+	char		newifname[LIFNAMSIZ];
+
+	/* Check for the required authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
+	    !(flags & IPADM_OPT_ACTIVE)) ||
+	    (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP |
+	    IPADM_OPT_GENPPA))) {
+		return (IPADM_INVALID_ARG);
+	}
+	if (flags & IPADM_OPT_GENPPA) {
+		if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >=
+		    LIFNAMSIZ)
+			return (IPADM_INVALID_ARG);
+	} else {
+		if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ)
+			return (IPADM_INVALID_ARG);
+	}
+
+	if (!i_ipadm_validate_ifname(iph, newifname))
+		return (IPADM_INVALID_ARG);
+
+	if ((af == AF_INET || af == AF_UNSPEC) &&
+	    !i_ipadm_is_6to4(iph, ifname)) {
+		status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		created_v4 = B_TRUE;
+	}
+	if (af == AF_INET6 || af == AF_UNSPEC) {
+		status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
+		if (status != IPADM_SUCCESS) {
+			if (created_v4) {
+				(void) i_ipadm_delete_if(iph, ifname, AF_INET,
+				    IPADM_OPT_ACTIVE);
+			}
+			return (status);
+		}
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
+ * when `af' = AF_UNSPEC.
+ */
+ipadm_status_t
+ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    uint32_t flags)
+{
+	ipadm_status_t status1 = IPADM_SUCCESS;
+	ipadm_status_t status2 = IPADM_SUCCESS;
+	ipadm_status_t other;
+
+	/* Check for the required authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* Validate the `ifname' for any logical interface. */
+	if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
+	    !i_ipadm_validate_ifname(iph, ifname))
+		return (IPADM_INVALID_ARG);
+
+	if (af == AF_INET || af == AF_UNSPEC)
+		status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags);
+	if (af == AF_INET6 || af == AF_UNSPEC)
+		status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags);
+	/*
+	 * If the family has been uniquely identified, we return the
+	 * associated status, even if that is ENXIO. Calls from ifconfig
+	 * which can only unplumb one of IPv4/IPv6 at any time fall under
+	 * this category.
+	 */
+	if (af == AF_INET)
+		return (status1);
+	else if (af == AF_INET6)
+		return (status2);
+	else if (af != AF_UNSPEC)
+		return (IPADM_INVALID_ARG);
+
+	/*
+	 * If af is AF_UNSPEC, then we return the following:
+	 * status1,		if status1 == status2
+	 * IPADM_SUCCESS,	if either of status1 or status2 is SUCCESS
+	 * 			and the other status is ENXIO
+	 * IPADM_ENXIO,		if both status1 and status2 are ENXIO
+	 * IPADM_FAILURE	otherwise.
+	 */
+	if (status1 == status2) {
+		/* covers the case when both status1 and status2 are ENXIO */
+		return (status1);
+	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
+		if (status1 == IPADM_SUCCESS)
+			other = status2;
+		else
+			other = status1;
+		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
+	} else {
+		return (IPADM_FAILURE);
+	}
+}
+
+/*
+ * Returns information about all interfaces in both active and persistent
+ * configuration. If `ifname' is not NULL, it returns only the interface
+ * identified by `ifname'.
+ *
+ * Return values:
+ * 	On success: IPADM_SUCCESS.
+ * 	On error  : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
+ */
+ipadm_status_t
+ipadm_if_info(ipadm_handle_t iph, const char *ifname,
+    ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
+{
+	ipadm_status_t	status;
+	ifspec_t	ifsp;
+
+	if (if_info == NULL || iph == NULL || flags != 0)
+		return (IPADM_INVALID_ARG);
+
+	if (ifname != NULL &&
+	    (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+	if (ifname != NULL && *if_info == NULL)
+		return (IPADM_ENXIO);
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Frees the linked list allocated by ipadm_if_info().
+ */
+void
+ipadm_free_if_info(ipadm_if_info_t *ifinfo)
+{
+	ipadm_if_info_t	*ifinfo_next;
+
+	for (; ifinfo != NULL; ifinfo = ifinfo_next) {
+		ifinfo_next = ifinfo->ifi_next;
+		free(ifinfo);
+	}
+}
+
+/*
+ * Re-enable the interface `ifname' based on the saved configuration
+ * for `ifname'.
+ */
+ipadm_status_t
+ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
+{
+	nvlist_t	*ifnvl;
+	ipadm_status_t	status;
+	ifspec_t	ifsp;
+
+	/* Check for the required authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* Check for logical interfaces. */
+	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
+		return (IPADM_INVALID_ARG);
+
+	/* Enabling an interface persistently is not supported. */
+	if (flags & IPADM_OPT_PERSIST)
+		return (IPADM_NOTSUP);
+
+	/*
+	 * Return early by checking if the interface is already enabled.
+	 */
+	if (ipadm_if_enabled(iph, ifname, AF_INET) &&
+	    ipadm_if_enabled(iph, ifname, AF_INET6)) {
+		return (IPADM_IF_EXISTS);
+	}
+	/*
+	 * Enable the interface and restore all its interface properties
+	 * and address objects.
+	 */
+	status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	assert(ifnvl != NULL);
+	/*
+	 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
+	 * but only for one interface. We need to set IPH_INIT because
+	 * ipmgmtd daemon does not have to write the interface to persistent
+	 * db. The interface is already available in persistent db
+	 * and we are here to re-enable the persistent configuration.
+	 */
+	iph->iph_flags |= IPH_INIT;
+	status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
+	iph->iph_flags &= ~IPH_INIT;
+	return (status);
+}
+
+/*
+ * Disable the interface `ifname' by removing it from the active configuration.
+ * Error code return values follow the model in ipadm_delete_if()
+ */
+ipadm_status_t
+ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
+{
+	ipadm_status_t	status1, status2, other;
+	ifspec_t	ifsp;
+
+	/* Check for the required authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	/* Check for logical interfaces. */
+	if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
+		return (IPADM_INVALID_ARG);
+
+	/* Disabling an interface persistently is not supported. */
+	if (flags & IPADM_OPT_PERSIST)
+		return (IPADM_NOTSUP);
+
+	status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
+	if (status1 == IPADM_SUCCESS)
+		status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
+	status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
+	if (status2 == IPADM_SUCCESS)
+		status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
+	if (status1 == status2) {
+		return (status2);
+	} else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
+		if (status1 == IPADM_SUCCESS)
+			other = status2;
+		else
+			other = status1;
+		return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
+	} else {
+		return (IPADM_FAILURE);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,272 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _IPADM_IPMGMT_H
+#define	_IPADM_IPMGMT_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <door.h>
+#include <libipadm.h>
+#include <inet/tunables.h>
+
+/*
+ * Function declarations and data structures shared by libipadm.so and
+ * the IP management daemon.
+ */
+
+/* Authorization required to configure network interfaces */
+#define	NETWORK_INTERFACE_CONFIG_AUTH	"solaris.network.interface.config"
+
+/*
+ * Data store read/write utilities related declarations.
+ */
+/* Permanent data store for ipadm */
+#define	IPADM_DB_FILE		"/etc/ipadm/ipadm.conf"
+#define	IPADM_FILE_MODE		(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+#define	IPADM_TMPFS_DIR		"/etc/svc/volatile/ipadm"
+
+/*
+ * 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.
+ */
+#define	IPADM_NVP_PROTONAME	"_protocol"	/* protocol name */
+#define	IPADM_NVP_IFNAME	"_ifname"	/* interface name */
+#define	IPADM_NVP_AOBJNAME	"_aobjname"	/* addrobj name */
+#define	IPADM_NVP_FAMILY	"_family"	/* address family */
+#define	IPADM_NVP_IPV4ADDR	"_ipv4addr"	/* name of IPv4 addr nvlist */
+#define	IPADM_NVP_IPNUMADDR	"_addr"		/* local address */
+#define	IPADM_NVP_IPADDRHNAME	"_aname"	/* local hostname */
+#define	IPADM_NVP_IPDADDRHNAME	"_dname"	/* remote hostname */
+#define	IPADM_NVP_PREFIXLEN	"prefixlen"	/* prefixlen */
+#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 */
+#define	IPADM_NVP_PRIMARY	"_primary"	/* DHCP primary interface */
+#define	IPADM_NVP_LIFNUM	"_lifnum"	/* logical interface number */
+#define	IPADM_NVP_INTFID	"_intfid"	/* name of IPv6 intfid nvlist */
+#define	IPADM_NVP_STATELESS	"_stateless"	/* IPv6 autoconf stateless */
+#define	IPADM_NVP_STATEFUL	"_stateful"	/* IPv6 autoconf dhcpv6 */
+
+#define	IPADM_PRIV_NVP(s) ((s)[0] == '_')
+
+/* data-store operations */
+typedef enum {
+	IPADM_DB_WRITE = 0,	/* Writes to DB */
+	IPADM_DB_DELETE,	/* Deletes an entry from DB */
+	IPADM_DB_READ		/* Read from DB */
+} ipadm_db_op_t;
+
+/*
+ * callback arg used by db_wfunc_t that writes to DB. The contents to be
+ * written to DB are captured in `dbw_nvl'.
+ */
+typedef	struct	ipadm_dbwrite_cbarg_s {
+	nvlist_t	*dbw_nvl;
+	uint_t		dbw_flags;
+} ipadm_dbwrite_cbarg_t;
+
+/*
+ * door related function declarations and data structures.
+ */
+
+/* The door file for the ipmgmt (ip-interface management) daemon */
+#define	IPMGMT_DOOR		"/etc/svc/volatile/ipadm/ipmgmt_door"
+#define	MAXPROTONAMELEN		32
+
+/* door call command type */
+typedef enum {
+	IPMGMT_CMD_SETPROP = 1,		/* persist property */
+	IPMGMT_CMD_SETIF,		/* persist interface */
+	IPMGMT_CMD_SETADDR,		/* persist address */
+	IPMGMT_CMD_GETPROP,		/* retrieve persisted property value */
+	IPMGMT_CMD_GETIF,		/* retrieve persisted interface conf. */
+	IPMGMT_CMD_GETADDR,		/* retrieve persisted addresses */
+	IPMGMT_CMD_RESETIF,		/* purge interface configuration */
+	IPMGMT_CMD_RESETADDR,		/* purge address configuration */
+	IPMGMT_CMD_RESETPROP,		/* purge property configuration */
+	IPMGMT_CMD_INITIF,		/* retrieve interfaces to initialize */
+	IPMGMT_CMD_ADDROBJ_LOOKUPADD,	/* addr. object lookup & add */
+	IPMGMT_CMD_ADDROBJ_ADD,		/* add addr. object to addrobj map */
+	IPMGMT_CMD_LIF2ADDROBJ,		/* lifname to addrobj mapping */
+	IPMGMT_CMD_AOBJNAME2ADDROBJ	/* aobjname to addrobj mapping */
+} ipmgmt_door_cmd_type_t;
+
+/*
+ * Note: We need to keep the size of the structure the same on amd64 and i386
+ * for all door_call arguments and door_return structures.
+ */
+/* door_call argument */
+typedef struct ipmgmt_arg {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+} ipmgmt_arg_t;
+
+/* IPMGMT_CMD_{SETPROP|GETPROP|RESETPROP} door_call argument */
+typedef struct ipmgmt_prop_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t		ia_flags;
+	char			ia_ifname[LIFNAMSIZ];
+	char			ia_aobjname[IPADM_AOBJSIZ];
+	char			ia_module[MAXPROTONAMELEN];
+	char			ia_pname[MAXPROPNAMELEN];
+	char			ia_pval[MAXPROPVALLEN];
+} ipmgmt_prop_arg_t;
+/*
+ * ia_flags used in ipmgmt_prop_arg_t.
+ *	- APPEND updates the multi-valued property entry with a new value
+ *	- REDUCE updates the multi-valued property entry by removing a value
+ */
+#define	IPMGMT_APPEND	0x00000001
+#define	IPMGMT_REMOVE	0x00000002
+
+/* IPMGMT_CMD_GETIF door_call argument structure */
+typedef struct ipmgmt_getif_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t	ia_flags;
+	char		ia_ifname[LIFNAMSIZ];
+} ipmgmt_getif_arg_t;
+
+/* IPMGMT_CMD_RESETIF, IPMGMT_CMD_SETIF door_call argument structure */
+typedef struct ipmgmt_if_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t		ia_flags;
+	char			ia_ifname[LIFNAMSIZ];
+	sa_family_t		ia_family;
+} ipmgmt_if_arg_t;
+
+/* IPMGMT_CMD_INITIF door_call argument structure */
+typedef struct ipmgmt_initif_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t	ia_flags;
+	sa_family_t	ia_family;
+	size_t		ia_nvlsize;
+	/* packed nvl follows */
+} ipmgmt_initif_arg_t;
+
+/* IPMGMT_CMD_SETADDR door_call argument */
+typedef struct ipmgmt_setaddr_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t		ia_flags;
+	size_t			ia_nvlsize;
+	/* packed nvl follows */
+} ipmgmt_setaddr_arg_t;
+
+/* IPMGMT_CMD_GETADDR door_call argument */
+typedef struct ipmgmt_getaddr_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t	ia_flags;
+	char		ia_ifname[LIFNAMSIZ];
+	sa_family_t	ia_family;
+	char		ia_aobjname[IPADM_AOBJSIZ];
+} ipmgmt_getaddr_arg_t;
+
+/* IPMGMT_CMD_RESETADDR door_call argument */
+typedef struct ipmgmt_addr_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t	ia_flags;
+	char		ia_aobjname[IPADM_AOBJSIZ];
+	int32_t		ia_lnum;
+} ipmgmt_addr_arg_t;
+
+/*
+ * IPMGMT_CMD_{ADDROBJ_ADD|ADDROBJ_LOOKUPADD|LIFNUM2ADDROBJ|
+ * ADDROBJ2LIFNUM} door_call argument.
+ */
+typedef struct ipmgmt_aobjop_arg_s {
+	ipmgmt_door_cmd_type_t	ia_cmd;
+	uint32_t		ia_flags;
+	char			ia_aobjname[IPADM_AOBJSIZ];
+	char			ia_ifname[LIFNAMSIZ];
+	int32_t			ia_lnum;
+	sa_family_t		ia_family;
+	ipadm_addr_type_t	ia_atype;
+} ipmgmt_aobjop_arg_t;
+
+/*
+ * ia_flags used inside the arguments for interface/address commands
+ *	- ACTIVE updates the running configuration
+ *	- PERSIST updates the permanent data store
+ *	- INIT	indicates that operation being performed is under init
+ *		    context
+ */
+#define	IPMGMT_ACTIVE		0x00000001
+#define	IPMGMT_PERSIST		0x00000002
+#define	IPMGMT_INIT		0x00000004
+
+/* door call return value */
+typedef struct ipmgmt_retval_s {
+	int32_t	ir_err;
+} ipmgmt_retval_t;
+
+/* IPMGMT_CMD_GETADDR door_return value */
+typedef struct ipmgmt_get_rval_s {
+	int32_t		ir_err;
+	size_t		ir_nvlsize;
+	/* packed nvl follows */
+} ipmgmt_get_rval_t;
+
+/* IPMGMT_CMD_GETPROP door_return value */
+typedef struct ipmgmt_getprop_rval_s {
+	int32_t		ir_err;
+	char		ir_pval[MAXPROPVALLEN];
+} ipmgmt_getprop_rval_t;
+
+/* IPMGMT_CMD_GETIF door_return value */
+typedef struct ipmgmt_getif_rval_s {
+	int32_t		ir_err;
+	uint32_t	ir_ifcnt;
+	ipadm_if_info_t	ir_ifinfo[1];
+} ipmgmt_getif_rval_t;
+
+/* IPMGMT_CMD_{LOOKUPADD|LIFNUM2ADDROBJ|ADDROBJ2LIFNUM} door_return value */
+typedef struct ipmgmt_aobjop_rval_s {
+	int32_t			ir_err;
+	char			ir_aobjname[IPADM_AOBJSIZ];
+	char			ir_ifname[LIFNAMSIZ];
+	int32_t			ir_lnum;
+	sa_family_t		ir_family;
+	uint32_t		ir_flags;
+	ipadm_addr_type_t	ir_atype;
+	struct sockaddr_storage	ir_ifid;
+} ipmgmt_aobjop_rval_t;
+
+/* 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,
+			    ipadm_db_op_t);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _IPADM_IPMGMT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_ndpd.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,366 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file contains the functions that are required for communicating
+ * with in.ndpd while creating autoconfigured addresses.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <inet/ip.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <poll.h>
+#include <ipadm_ndpd.h>
+#include "libipadm_impl.h"
+
+#define	NDPDTIMEOUT		5000
+#define	PREFIXLEN_LINKLOCAL	10
+
+static ipadm_status_t	i_ipadm_create_linklocal(ipadm_handle_t,
+			    ipadm_addrobj_t);
+static void		i_ipadm_make_linklocal(struct sockaddr_in6 *,
+			    const struct in6_addr *);
+static ipadm_status_t	i_ipadm_send_ndpd_cmd(const char *,
+			    const struct ipadm_addrobj_s *, int);
+
+/*
+ * Sends message to in.ndpd asking not to do autoconf for the given interface,
+ * until IPADM_CREATE_ADDRS or IPADM_ENABLE_AUTOCONF is sent.
+ */
+ipadm_status_t
+i_ipadm_disable_autoconf(const char *ifname)
+{
+	return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_DISABLE_AUTOCONF));
+}
+
+/*
+ * Sends message to in.ndpd to enable autoconf for the given interface,
+ * until another IPADM_DISABLE_AUTOCONF is sent.
+ */
+ipadm_status_t
+i_ipadm_enable_autoconf(const char *ifname)
+{
+	return (i_ipadm_send_ndpd_cmd(ifname, NULL, IPADM_ENABLE_AUTOCONF));
+}
+
+ipadm_status_t
+i_ipadm_create_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t addr,
+    uint32_t i_flags)
+{
+	ipadm_status_t status;
+
+	/*
+	 * Create the link local based on the given token. If the same intfid
+	 * was already used with a different address object, this step will
+	 * fail.
+	 */
+	status = i_ipadm_create_linklocal(iph, addr);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	/*
+	 * Request in.ndpd to start the autoconfiguration.
+	 * If autoconfiguration was already started by another means (e.g.
+	 * "ifconfig" ), in.ndpd will return EEXIST.
+	 */
+	if (addr->ipadm_stateless || addr->ipadm_stateful) {
+		status = i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
+		    IPADM_CREATE_ADDRS);
+		if (status != IPADM_SUCCESS &&
+		    status != IPADM_NDPD_NOT_RUNNING) {
+			(void) i_ipadm_delete_addr(iph, addr);
+			return (status);
+		}
+	}
+
+	/* Persist the intfid. */
+	status = i_ipadm_addr_persist(iph, addr, B_FALSE, i_flags);
+	if (status != IPADM_SUCCESS) {
+		(void) i_ipadm_delete_addr(iph, addr);
+		(void) i_ipadm_send_ndpd_cmd(addr->ipadm_ifname, addr,
+		    IPADM_DELETE_ADDRS);
+	}
+
+	return (status);
+}
+
+ipadm_status_t
+i_ipadm_delete_ipv6addrs(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
+{
+	ipadm_status_t status;
+
+	/*
+	 * Send a msg to in.ndpd to remove the autoconfigured addresses,
+	 * and delete the link local that was created.
+	 */
+	status = i_ipadm_send_ndpd_cmd(ipaddr->ipadm_ifname, ipaddr,
+	    IPADM_DELETE_ADDRS);
+	if (status == IPADM_NDPD_NOT_RUNNING)
+		status = IPADM_SUCCESS;
+	if (status == IPADM_SUCCESS)
+		status = i_ipadm_delete_addr(iph, ipaddr);
+
+	return (status);
+}
+
+static ipadm_status_t
+i_ipadm_create_linklocal(ipadm_handle_t iph, ipadm_addrobj_t addr)
+{
+	boolean_t addif = B_FALSE;
+	struct sockaddr_in6 *sin6;
+	struct lifreq lifr;
+	int err;
+	ipadm_status_t status;
+	in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, LIFNAMSIZ);
+
+	if ((err = ioctl(iph->iph_sock6, SIOCGLIFADDR, (caddr_t)&lifr)) < 0)
+		return (ipadm_errno2status(errno));
+
+	/*
+	 * If no address exists on 0th logical interface,
+	 * create link-local address on it. Else, create a new
+	 * logical interface.
+	 */
+	sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
+	if (!IN6_IS_ADDR_UNSPECIFIED((&sin6->sin6_addr))) {
+		if (ioctl(iph->iph_sock6, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
+		addif = B_TRUE;
+	}
+	/* Create the link-local address */
+	bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
+	(void) plen2mask(PREFIXLEN_LINKLOCAL, AF_INET6, &lifr.lifr_addr);
+	if ((err = ioctl(iph->iph_sock6, SIOCSLIFNETMASK, (caddr_t)&lifr)) < 0)
+		goto fail;
+	if (addr->ipadm_intfidlen == 0) {
+		/*
+		 * If we have to use the default interface id,
+		 * we just need to set the prefix to the link-local prefix.
+		 * SIOCSLIFPREFIX sets the address with the given prefix
+		 * and the default interface id.
+		 */
+		sin6->sin6_addr = ll_template;
+		err = ioctl(iph->iph_sock6, SIOCSLIFPREFIX, (caddr_t)&lifr);
+		if (err < 0)
+			goto fail;
+	} else {
+		/* Make a linklocal address in sin6 and set it */
+		i_ipadm_make_linklocal(sin6, &addr->ipadm_intfid.sin6_addr);
+		err = ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
+		if (err < 0)
+			goto fail;
+	}
+	if ((err = ioctl(iph->iph_sock6, SIOCGLIFFLAGS, (char *)&lifr)) < 0)
+		goto fail;
+	lifr.lifr_flags |= IFF_UP;
+	if ((err = ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (char *)&lifr)) < 0)
+		goto fail;
+	return (IPADM_SUCCESS);
+
+fail:
+	if (errno == EEXIST)
+		status = IPADM_ADDRCONF_EXISTS;
+	else
+		status = ipadm_errno2status(errno);
+	/* Remove the linklocal that was created. */
+	if (addif) {
+		(void) ioctl(iph->iph_sock6, SIOCLIFREMOVEIF, (caddr_t)&lifr);
+	} else {
+		struct sockaddr_in6 *sin6;
+
+		sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr;
+		lifr.lifr_flags &= ~IFF_UP;
+		(void) ioctl(iph->iph_sock6, SIOCSLIFFLAGS, (caddr_t)&lifr);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_addr = in6addr_any;
+		(void) ioctl(iph->iph_sock6, SIOCSLIFADDR, (caddr_t)&lifr);
+	}
+	return (status);
+}
+
+/*
+ * Make a linklocal address based on the given intfid and copy it into
+ * the output parameter `sin6'.
+ */
+static void
+i_ipadm_make_linklocal(struct sockaddr_in6 *sin6, const struct in6_addr *intfid)
+{
+	int i;
+	in6_addr_t ll_template = {0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+	    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
+
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_addr = *intfid;
+	for (i = 0; i < 4; i++) {
+		sin6->sin6_addr.s6_addr[i] =
+		    sin6->sin6_addr.s6_addr[i] | ll_template.s6_addr[i];
+	}
+}
+
+/*
+ * Function that forms an ndpd msg and sends it to the in.ndpd daemon's loopback
+ * listener socket.
+ */
+static ipadm_status_t
+i_ipadm_send_ndpd_cmd(const char *ifname, const struct ipadm_addrobj_s *addr,
+    int cmd)
+{
+	int fd;
+	struct sockaddr_un servaddr;
+	int flags;
+	ipadm_ndpd_msg_t msg;
+	int retval;
+
+	if (addr == NULL &&
+	    (cmd == IPADM_CREATE_ADDRS || cmd == IPADM_DELETE_ADDRS)) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	fd = socket(AF_UNIX, SOCK_STREAM, 0);
+	if (fd == -1)
+		return (IPADM_FAILURE);
+
+	/* Put the socket in non-blocking mode */
+	flags = fcntl(fd, F_GETFL, 0);
+	if (flags != -1)
+		(void) fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+	/* Connect to in.ndpd */
+	bzero(&servaddr, sizeof (servaddr));
+	servaddr.sun_family = AF_UNIX;
+	(void) strlcpy(servaddr.sun_path, IPADM_UDS_PATH,
+	    sizeof (servaddr.sun_path));
+	if (connect(fd, (struct sockaddr *)&servaddr, sizeof (servaddr)) == -1)
+		goto fail;
+
+	bzero(&msg, sizeof (msg));
+	msg.inm_cmd = cmd;
+	(void) strlcpy(msg.inm_ifname, ifname, sizeof (msg.inm_ifname));
+	if (addr != NULL) {
+		msg.inm_intfid = addr->ipadm_intfid;
+		msg.inm_intfidlen = addr->ipadm_intfidlen;
+		msg.inm_stateless = addr->ipadm_stateless;
+		msg.inm_stateful = addr->ipadm_stateful;
+		if (cmd == IPADM_CREATE_ADDRS) {
+			(void) strlcpy(msg.inm_aobjname, addr->ipadm_aobjname,
+			    sizeof (msg.inm_aobjname));
+		}
+	}
+	if (ipadm_ndpd_write(fd, &msg, sizeof (msg)) < 0)
+		goto fail;
+	if (ipadm_ndpd_read(fd, &retval, sizeof (retval)) < 0)
+		goto fail;
+	(void) close(fd);
+	if (cmd == IPADM_CREATE_ADDRS && retval == EEXIST)
+		return (IPADM_ADDRCONF_EXISTS);
+	return (ipadm_errno2status(retval));
+fail:
+	(void) close(fd);
+	return (IPADM_NDPD_NOT_RUNNING);
+}
+
+/*
+ * Attempt to read `buflen' worth of bytes from `fd' into the buffer pointed
+ * to by `buf'.
+ */
+int
+ipadm_ndpd_read(int fd, void *buffer, size_t buflen)
+{
+	int		retval;
+	ssize_t		nbytes = 0;	/* total bytes processed */
+	ssize_t		prbytes;	/* per-round bytes processed */
+	struct pollfd	pfd;
+
+	while (nbytes < buflen) {
+
+		pfd.fd = fd;
+		pfd.events = POLLIN;
+
+		/*
+		 * Wait for data to come in or for the timeout to fire.
+		 */
+		retval = poll(&pfd, 1, NDPDTIMEOUT);
+		if (retval <= 0) {
+			if (retval == 0)
+				errno = ETIME;
+			break;
+		}
+
+		/*
+		 * Descriptor is ready; have at it.
+		 */
+		prbytes = read(fd, (caddr_t)buffer + nbytes, buflen - nbytes);
+		if (prbytes <= 0) {
+			if (prbytes == -1 && errno == EINTR)
+				continue;
+			break;
+		}
+		nbytes += prbytes;
+	}
+
+	return (nbytes == buflen ? 0 : -1);
+}
+
+/*
+ * Write `buflen' bytes from `buffer' to open file `fd'.  Returns 0
+ * if all requested bytes were written, or an error code if not.
+ */
+int
+ipadm_ndpd_write(int fd, const void *buffer, size_t buflen)
+{
+	size_t		nwritten;
+	ssize_t		nbytes;
+	const char	*buf = buffer;
+
+	for (nwritten = 0; nwritten < buflen; nwritten += nbytes) {
+		nbytes = write(fd, &buf[nwritten], buflen - nwritten);
+		if (nbytes == -1)
+			return (-1);
+		if (nbytes == 0) {
+			errno = EIO;
+			return (-1);
+		}
+	}
+
+	assert(nwritten == buflen);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_ndpd.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,72 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _IPADM_NDPD_H
+#define	_IPADM_NDPD_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+#include <libipadm.h>
+
+/* File used for the AF_UNIX socket used in communicating with in.ndpd */
+#define	IPADM_UDS_PATH	"/var/run/in.ndpd_ipadm"
+
+/* Types of messages sent to in.ndpd */
+enum {
+	IPADM_DISABLE_AUTOCONF,
+	IPADM_ENABLE_AUTOCONF,
+	IPADM_CREATE_ADDRS,
+	IPADM_DELETE_ADDRS
+};
+
+/* Message format sent to in.ndpd */
+typedef struct ipadm_ndpd_msg_s {
+	uint32_t		inm_cmd;
+	char			inm_ifname[LIFNAMSIZ];
+	struct sockaddr_in6	inm_intfid;
+	int			inm_intfidlen;
+	boolean_t		inm_stateless;
+	boolean_t		inm_stateful;
+	char			inm_aobjname[MAXNAMELEN];
+} ipadm_ndpd_msg_t;
+
+/* Functions to send to and receive from in.ndpd */
+extern int		ipadm_ndpd_write(int, const void *, size_t);
+extern int		ipadm_ndpd_read(int, void *, size_t);
+
+/*
+ * Functions used by in.ndpd to add and delete address objects while
+ * adding/deleting each stateless/stateful autoconfigured address.
+ */
+extern ipadm_status_t	ipadm_add_aobjname(ipadm_handle_t, const char *,
+			    sa_family_t, const char *, ipadm_addr_type_t, int);
+extern ipadm_status_t	ipadm_delete_aobjname(ipadm_handle_t, const char *,
+			    sa_family_t, const char *, ipadm_addr_type_t, int);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _IPADM_NDPD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_persist.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,828 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file contains routines to read/write formatted entries from/to
+ * libipadm data store /etc/ipadm/ipadm.conf. Each entry in the DB is a
+ * series of IPADM_NVPAIR_SEP separated (name, value) pairs, as shown
+ * below:
+ *		name=value[;...]
+ *
+ * The 'name' determines how to interpret 'value'. The supported names are:
+ *
+ *  IPADM_NVP_IPV6ADDR - value holds local and remote IPv6 addresses and when
+ *	       converted to nvlist, will contain nvpairs for local and remote
+ *	       addresses. These nvpairs are of type DATA_TYPE_STRING
+ *
+ *  IPADM_NVP_IPV4ADDR - value holds local and remote IPv4 addresses and when
+ *	       converted to nvlist, will contain nvpairs for local and remote
+ *	       addresses. These nvpairs are of type DATA_TYPE_STRING
+ *
+ *  IPADM_NVP_INTFID - value holds token, prefixlen, stateless and stateful
+ *	       info and when converted to nvlist, will contain following nvpairs
+ *			interface_id: DATA_TYPE_UINT8_ARRAY
+ *			prefixlen: DATA_TYPE_UINT32
+ *			stateless: DATA_TYPE_STRING
+ *			stateful: DATA_TYPE_STRING
+ *
+ *  IPADM_NVP_DHCP - value holds wait time and primary info and when converted
+ *	       to nvlist, will contain following nvpairs
+ *			wait:	DATA_TYPE_INT32
+ *			primary: DATA_TYPE_BOOLEAN
+ *
+ *  default  - value is a single entity and when converted to nvlist, will
+ *	       contain nvpair of type DATA_TYPE_STRING. nvpairs private to
+ *	       ipadm are of this type. Further the property name and property
+ *	       values are stored as nvpairs of this type.
+ *
+ * The syntax for each line is described above the respective functions below.
+ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/dld.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/sockio.h>
+#include "libipadm_impl.h"
+
+#define	MAXLINELEN		1024
+#define	IPADM_NVPAIR_SEP	";"
+#define	IPADM_NAME_SEP		","
+
+static char ipadm_rootdir[MAXPATHLEN] = "/";
+
+static int ipadm_process_db_line(db_wfunc_t *, void *, FILE *fp, FILE *nfp,
+    ipadm_db_op_t);
+
+/*
+ * convert nvpair to a "name=value" string for writing to the DB.
+ */
+typedef size_t  ipadm_wfunc_t(nvpair_t *, char *, size_t);
+
+/*
+ * ipadm_rfunc_t takes (`name', `value') and adds the appropriately typed
+ * nvpair to the nvlist.
+ */
+typedef void  ipadm_rfunc_t(nvlist_t *, char *name, char *value);
+
+static ipadm_rfunc_t	i_ipadm_str_dbline2nvl, i_ipadm_ip4_dbline2nvl,
+			i_ipadm_ip6_dbline2nvl, i_ipadm_intfid_dbline2nvl,
+			i_ipadm_dhcp_dbline2nvl;
+
+static ipadm_wfunc_t	i_ipadm_str_nvp2dbline, i_ipadm_ip4_nvp2dbline,
+			i_ipadm_ip6_nvp2dbline, i_ipadm_intfid_nvp2dbline,
+			i_ipadm_dhcp_nvp2dbline;
+
+/*
+ * table of function pointers to read/write formatted entries from/to
+ * ipadm.conf.
+ */
+typedef struct ipadm_conf_ent_s {
+	const char		*ipent_type_name;
+	ipadm_wfunc_t		*ipent_wfunc;
+	ipadm_rfunc_t		*ipent_rfunc;
+} ipadm_conf_ent_t;
+
+static ipadm_conf_ent_t ipadm_conf_ent[] = {
+	{ IPADM_NVP_IPV6ADDR, i_ipadm_ip6_nvp2dbline, i_ipadm_ip6_dbline2nvl },
+	{ IPADM_NVP_IPV4ADDR, i_ipadm_ip4_nvp2dbline, i_ipadm_ip4_dbline2nvl },
+	{ IPADM_NVP_INTFID, i_ipadm_intfid_nvp2dbline,
+	    i_ipadm_intfid_dbline2nvl },
+	{ IPADM_NVP_DHCP, i_ipadm_dhcp_nvp2dbline, i_ipadm_dhcp_dbline2nvl },
+	{ NULL,	i_ipadm_str_nvp2dbline,	i_ipadm_str_dbline2nvl }
+};
+
+static ipadm_conf_ent_t *
+i_ipadm_find_conf_type(const char *type)
+{
+	int	i;
+
+	for (i = 0; ipadm_conf_ent[i].ipent_type_name != NULL; i++)
+		if (strcmp(type, ipadm_conf_ent[i].ipent_type_name) == 0)
+			break;
+	return (&ipadm_conf_ent[i]);
+}
+
+/*
+ * Extracts the hostnames IPADM_NVP_IPADDRHNAME and IPADM_NVP_IPDADDRHNAME from
+ * the given nvlist `nvl' and adds the strings to `buf'.
+ */
+size_t
+i_ipadm_ip_addhostname2dbline(nvlist_t *nvl, char *buf, size_t buflen)
+{
+	char	*cp;
+	char	tmpbuf[IPADM_STRSIZE];
+
+	/* Add the local hostname */
+	if (nvlist_lookup_string(nvl, IPADM_NVP_IPADDRHNAME, &cp) != 0)
+		return (0);
+	(void) strlcat(buf, cp, buflen); /* local hostname */
+
+	/* Add the dst hostname */
+	if (nvlist_lookup_string(nvl, IPADM_NVP_IPDADDRHNAME, &cp) != 0) {
+		/* no dst addr. just add a NULL character */
+		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",");
+	} else {
+		(void) snprintf(tmpbuf, sizeof (tmpbuf), ",%s", cp);
+	}
+	return (strlcat(buf, tmpbuf, buflen));
+}
+
+/*
+ * Converts IPADM_NVP_IPV4ADDR nvpair to a string representation for writing to
+ * the DB. The converted string format:
+ *	ipv4addr=<local numeric IP string or hostname,remote numeric IP
+ *          string or hostname>
+ */
+static size_t
+i_ipadm_ip4_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+	nvlist_t	*v;
+	int		nbytes;
+
+	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
+	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV4ADDR) == 0);
+
+	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV4ADDR);
+	if (nvpair_value_nvlist(nvp, &v) != 0)
+		goto fail;
+	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
+	if (nbytes != 0)
+		return (nbytes);
+fail:
+	buf[0] = '\0';
+	return (0);
+}
+
+/*
+ * Converts IPADM_NVP_IPV6ADDR nvpair to a string representation for writing to
+ * the DB. The converted string format:
+ *	ipv6addr=<local numeric IP string or hostname,remote numeric IP
+ *          string or hostname>
+ */
+static size_t
+i_ipadm_ip6_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+	nvlist_t	*v;
+	int		nbytes;
+
+	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
+	    strcmp(nvpair_name(nvp), IPADM_NVP_IPV6ADDR) == 0);
+
+	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_IPV6ADDR);
+	if (nvpair_value_nvlist(nvp, &v) != 0)
+		goto fail;
+	nbytes = i_ipadm_ip_addhostname2dbline(v, buf, buflen);
+	if (nbytes != 0)
+		return (nbytes);
+fail:
+	buf[0] = '\0';
+	return (0);
+}
+
+/*
+ * Converts IPADM_NVP_INTFID nvpair to a string representation for writing to
+ * the DB. The converted string format:
+ *	IPADM_NVP_INTFID=<intfid/prefixlen>,{yes|no},{yes|no}
+ */
+static size_t
+i_ipadm_intfid_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+	char		addrbuf[IPADM_STRSIZE];
+	nvlist_t	*v;
+	uint32_t	prefixlen;
+	struct in6_addr	in6addr;
+	char		*stateless;
+	char		*stateful;
+
+	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
+	    strcmp(nvpair_name(nvp), IPADM_NVP_INTFID) == 0);
+
+	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_INTFID);
+	if (nvpair_value_nvlist(nvp, &v) != 0)
+		goto fail;
+	if (i_ipadm_nvl2in6_addr(v, IPADM_NVP_IPNUMADDR, &in6addr) !=
+	    IPADM_SUCCESS)
+		goto fail;
+	(void) inet_ntop(AF_INET6, &in6addr, addrbuf,
+	    sizeof (addrbuf));
+	(void) strlcat(buf, addrbuf, buflen);
+	if (nvlist_lookup_uint32(v, IPADM_NVP_PREFIXLEN, &prefixlen) != 0 ||
+	    nvlist_lookup_string(v, IPADM_NVP_STATELESS, &stateless) != 0 ||
+	    nvlist_lookup_string(v, IPADM_NVP_STATEFUL, &stateful) != 0)
+		goto fail;
+	(void) snprintf(addrbuf, sizeof (addrbuf), "/%d,%s,%s",
+	    prefixlen, stateless, stateful);
+	return (strlcat(buf, addrbuf, buflen));
+fail:
+	buf[0] = '\0';
+	return (0);
+}
+
+/*
+ * Converts IPADM_NVP_DHCP nvpair to a string representation for writing to the
+ * DB. The converted string format:
+ *	IPADM_NVP_DHCP=<wait_time>,{yes|no}
+ */
+static size_t
+i_ipadm_dhcp_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+	char		addrbuf[IPADM_STRSIZE];
+	int32_t 	wait;
+	boolean_t	primary;
+	nvlist_t	*v;
+
+	assert(nvpair_type(nvp) == DATA_TYPE_NVLIST &&
+	    strcmp(nvpair_name(nvp), IPADM_NVP_DHCP) == 0);
+
+	if (nvpair_value_nvlist(nvp, &v) != 0 ||
+	    nvlist_lookup_int32(v, IPADM_NVP_WAIT, &wait) != 0 ||
+	    nvlist_lookup_boolean_value(v, IPADM_NVP_PRIMARY, &primary) != 0) {
+		return (0);
+	}
+	(void) snprintf(buf, buflen, "%s=", IPADM_NVP_DHCP);
+	(void) snprintf(addrbuf, sizeof (addrbuf), "%d,%s", wait,
+	    (primary ? "yes" : "no"));
+	return (strlcat(buf, addrbuf, buflen));
+}
+
+/*
+ * Constructs a "<name>=<value>" string from the nvpair, whose type must
+ * be STRING.
+ */
+static size_t
+i_ipadm_str_nvp2dbline(nvpair_t *nvp, char *buf, size_t buflen)
+{
+	char	*str = NULL;
+
+	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
+	if (nvpair_value_string(nvp, &str) != 0)
+		return (0);
+	return (snprintf(buf, buflen, "%s=%s", nvpair_name(nvp), str));
+}
+
+/*
+ * Converts a nvlist to string of the form:
+ *  <prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
+ */
+size_t
+ipadm_nvlist2str(nvlist_t *nvl, char *buf, size_t buflen)
+{
+	nvpair_t	*nvp = NULL;
+	uint_t		nbytes = 0, tbytes = 0;
+	ipadm_conf_ent_t *ipent;
+	size_t		bufsize = buflen;
+
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		ipent = i_ipadm_find_conf_type(nvpair_name(nvp));
+		nbytes = (*ipent->ipent_wfunc)(nvp, buf, buflen);
+		/* add nvpair separator */
+		nbytes += snprintf(buf + nbytes, buflen - nbytes, "%s",
+		    IPADM_NVPAIR_SEP);
+		buflen -= nbytes;
+		buf += nbytes;
+		tbytes += nbytes;
+		if (tbytes >= bufsize)	/* buffer overflow */
+			return (0);
+	}
+	nbytes = snprintf(buf, buflen, "%c%c", '\n', '\0');
+	tbytes += nbytes;
+	if (tbytes >= bufsize)
+		return (0);
+	return (tbytes);
+}
+
+/*
+ * Adds a nvpair, using the `name' and `value', to the nvlist in `nvl'.
+ * The value will be interpreted as explained at the top of this file.
+ */
+static void
+i_ipadm_add_nvpair(nvlist_t *nvl, char *name, char *value)
+{
+	ipadm_conf_ent_t	*ipent;
+
+	ipent = i_ipadm_find_conf_type(name);
+	(*ipent->ipent_rfunc)(nvl, name, value);
+}
+
+/*
+ * Adds an nvpair for IPv4 addr to the nvlist. The "name" is the string in
+ * IPADM_NVP_IPV4ADDR. The "value" for IPADM_NVP_IPV4ADDR is another nvlist.
+ * Allocate the value nvlist for IPADM_NVP_IPV4ADDR if necessary, and add
+ * the address and hostnames from the address object `ipaddr' to it.
+ * Then add the allocated nvlist to `nvl'.
+ */
+ipadm_status_t
+i_ipadm_add_ipaddr2nvl(nvlist_t *nvl, ipadm_addrobj_t ipaddr)
+{
+	nvlist_t		*nvl_addr = NULL;
+	int			err;
+	char			*name;
+	sa_family_t		af = ipaddr->ipadm_af;
+
+	if (af == AF_INET) {
+		name = IPADM_NVP_IPV4ADDR;
+	} else {
+		assert(af == AF_INET6);
+		name = IPADM_NVP_IPV6ADDR;
+	}
+
+	if (!nvlist_exists(nvl, name)) {
+		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
+			return (ipadm_errno2status(err));
+		if ((err = nvlist_add_nvlist(nvl, name, nvl_addr)) != 0) {
+			nvlist_free(nvl_addr);
+			return (ipadm_errno2status(err));
+		}
+		nvlist_free(nvl_addr);
+	}
+	if ((err = nvlist_lookup_nvlist(nvl, name, &nvl_addr)) != 0 ||
+	    (err = nvlist_add_string(nvl_addr, IPADM_NVP_IPADDRHNAME,
+	    ipaddr->ipadm_static_aname)) != 0)
+		return (ipadm_errno2status(err));
+	if (!sockaddrunspec(&ipaddr->ipadm_static_dst_addr)) {
+		if ((err = nvlist_add_string(nvl_addr, IPADM_NVP_IPDADDRHNAME,
+		    ipaddr->ipadm_static_dname)) != 0)
+			return (ipadm_errno2status(err));
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Adds an nvpair for IPv6 interface id to the nvlist. The "name" is
+ * the string in IPADM_NVP_INTFID. The "value" for IPADM_NVP_INTFID is another
+ * nvlist. Allocate the value nvlist for IPADM_NVP_INTFID if necessary, and add
+ * the interface id and its prefixlen from the address object `ipaddr' to it.
+ * Then add the allocated nvlist to `nvl'.
+ */
+ipadm_status_t
+i_ipadm_add_intfid2nvl(nvlist_t *nvl, ipadm_addrobj_t addr)
+{
+	nvlist_t	*nvl_addr = NULL;
+	struct in6_addr	addr6;
+	int		err;
+
+	if (!nvlist_exists(nvl, IPADM_NVP_INTFID)) {
+		if ((err = nvlist_alloc(&nvl_addr, NV_UNIQUE_NAME, 0)) != 0)
+			return (ipadm_errno2status(err));
+		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_INTFID,
+		    nvl_addr)) != 0) {
+			nvlist_free(nvl_addr);
+			return (ipadm_errno2status(err));
+		}
+		nvlist_free(nvl_addr);
+	}
+	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_INTFID,
+	    &nvl_addr)) != 0 || (err = nvlist_add_uint32(nvl_addr,
+	    IPADM_NVP_PREFIXLEN, addr->ipadm_intfidlen)) != 0) {
+		return (ipadm_errno2status(err));
+	}
+	addr6 = addr->ipadm_intfid.sin6_addr;
+	if ((err = nvlist_add_uint8_array(nvl_addr, IPADM_NVP_IPNUMADDR,
+	    addr6.s6_addr, 16)) != 0) {
+		return (ipadm_errno2status(err));
+	}
+	if (addr->ipadm_stateless)
+		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "yes");
+	else
+		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATELESS, "no");
+	if (err != 0)
+		return (ipadm_errno2status(err));
+	if (addr->ipadm_stateful)
+		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "yes");
+	else
+		err = nvlist_add_string(nvl_addr, IPADM_NVP_STATEFUL, "no");
+	if (err != 0)
+		return (ipadm_errno2status(err));
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Adds an nvpair for a dhcp address object to the nvlist. The "name" is
+ * the string in IPADM_NVP_DHCP. The "value" for IPADM_NVP_DHCP is another
+ * nvlist. Allocate the value nvlist for IPADM_NVP_DHCP if necessary, and add
+ * the parameters from the arguments `primary' and `wait'.
+ * Then add the allocated nvlist to `nvl'.
+ */
+ipadm_status_t
+i_ipadm_add_dhcp2nvl(nvlist_t *nvl, boolean_t primary, int32_t wait)
+{
+	nvlist_t	*nvl_dhcp = NULL;
+	int		err;
+
+	if (!nvlist_exists(nvl, IPADM_NVP_DHCP)) {
+		if ((err = nvlist_alloc(&nvl_dhcp, NV_UNIQUE_NAME, 0)) != 0)
+			return (ipadm_errno2status(err));
+		if ((err = nvlist_add_nvlist(nvl, IPADM_NVP_DHCP,
+		    nvl_dhcp)) != 0) {
+			nvlist_free(nvl_dhcp);
+			return (ipadm_errno2status(err));
+		}
+		nvlist_free(nvl_dhcp);
+	}
+	if ((err = nvlist_lookup_nvlist(nvl, IPADM_NVP_DHCP, &nvl_dhcp)) != 0 ||
+	    (err = nvlist_add_int32(nvl_dhcp, IPADM_NVP_WAIT, wait)) != 0 ||
+	    (err = nvlist_add_boolean_value(nvl_dhcp, IPADM_NVP_PRIMARY,
+	    primary)) != 0) {
+		return (ipadm_errno2status(err));
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Add (name, value) as an nvpair of type DATA_TYPE_STRING to nvlist.
+ */
+static void
+i_ipadm_str_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+	/* if value is NULL create an empty node */
+	if (value == NULL)
+		(void) nvlist_add_string(nvl, name, "");
+	else
+		(void) nvlist_add_string(nvl, name, value);
+}
+
+/*
+ * `name' = IPADM_NVP_IPV4ADDR and
+ * `value' = <local numeric IP string or hostname,remote numeric IP string or
+ *     hostname>
+ * This function will add an nvlist with the hostname information in
+ * nvpairs to the nvlist in `nvl'.
+ */
+static void
+i_ipadm_ip4_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+	char			*cp, *hname;
+	struct ipadm_addrobj_s	ipaddr;
+
+	assert(strcmp(name, IPADM_NVP_IPV4ADDR) == 0 && value != NULL);
+
+	bzero(&ipaddr, sizeof (ipaddr));
+	ipaddr.ipadm_af = AF_INET;
+
+	hname = value; /* local hostname */
+	cp = strchr(hname, ',');
+	assert(cp != NULL);
+	*cp++ = '\0';
+	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
+	    sizeof (ipaddr.ipadm_static_aname));
+
+	if (*cp != '\0') {
+		/* we have a dst hostname */
+		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
+		    sizeof (ipaddr.ipadm_static_dname));
+	}
+	(void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
+}
+
+/*
+ * `name' = IPADM_NVP_IPV6ADDR and
+ * `value' = <local numeric IP string or hostname,remote numeric IP string or
+ *     hostname>
+ * This function will add an nvlist with the hostname information in
+ * nvpairs to the nvlist in `nvl'.
+ */
+static void
+i_ipadm_ip6_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+	char			*cp, *hname;
+	struct ipadm_addrobj_s	ipaddr;
+
+	assert(strcmp(name, IPADM_NVP_IPV6ADDR) == 0 && value != NULL);
+
+	bzero(&ipaddr, sizeof (ipaddr));
+	ipaddr.ipadm_af = AF_INET6;
+
+	hname = value; /* local hostname */
+	cp = strchr(hname, ',');
+	assert(cp != NULL);
+	*cp++ = '\0';
+	(void) strlcpy(ipaddr.ipadm_static_aname, hname,
+	    sizeof (ipaddr.ipadm_static_aname));
+
+	if (*cp != '\0') {
+		/* we have a dst hostname */
+		(void) strlcpy(ipaddr.ipadm_static_dname, cp,
+		    sizeof (ipaddr.ipadm_static_dname));
+	}
+	(void) i_ipadm_add_ipaddr2nvl(nvl, &ipaddr);
+}
+
+/*
+ * `name' = IPADM_NVP_INTFID and `value' = <intfid/prefixlen>,{yes,no},{yes|no}
+ * This function will add an nvlist with the address object information in
+ * nvpairs to the nvlist in `nvl'.
+ */
+static void
+i_ipadm_intfid_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+	char			*cp;
+	struct ipadm_addrobj_s	ipaddr;
+	char			*endp;
+	char			*prefixlen;
+	char			*stateless;
+	char			*stateful;
+
+	assert(strcmp(name, IPADM_NVP_INTFID) == 0 && value != NULL);
+
+	bzero(&ipaddr, sizeof (ipaddr));
+
+	cp = strchr(value, '/');
+	assert(cp != NULL);
+
+	*cp++ = '\0';
+	ipaddr.ipadm_intfid.sin6_family = AF_INET6;
+	(void) inet_pton(AF_INET6, value, &ipaddr.ipadm_intfid.sin6_addr);
+
+	prefixlen = cp;
+	cp = strchr(cp, ',');
+	assert(cp != NULL);
+	*cp++ = '\0';
+
+	errno = 0;
+	ipaddr.ipadm_intfidlen = (uint32_t)strtoul(prefixlen, &endp, 10);
+	if (*endp != '\0' || errno != 0)
+		return;
+
+	stateless = cp;
+	stateful = strchr(stateless, ',');
+	assert(stateful != NULL);
+	*stateful++ = '\0';
+	ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
+	ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
+
+	/* Add all of it to the given nvlist */
+	(void) i_ipadm_add_intfid2nvl(nvl, &ipaddr);
+}
+
+/*
+ * `name' = IPADM_NVP_DHCP and `value' = <wait_time>,{yes|no}
+ * This function will add an nvlist with the dhcp address object information in
+ * nvpairs to the nvlist in `nvl'.
+ */
+static void
+i_ipadm_dhcp_dbline2nvl(nvlist_t *nvl, char *name, char *value)
+{
+	char		*cp;
+	char		*endp;
+	long		wait_time;
+	boolean_t	primary;
+
+	assert(strcmp(name, IPADM_NVP_DHCP) == 0 && value != NULL);
+	cp = strchr(value, ',');
+	assert(cp != NULL);
+	*cp++ = '\0';
+	errno = 0;
+	wait_time = strtol(value, &endp, 10);
+	if (*endp != '\0' || errno != 0)
+		return;
+	primary = (strcmp(cp, "yes") == 0);
+	(void) i_ipadm_add_dhcp2nvl(nvl, primary, (int32_t)wait_time);
+}
+
+/*
+ * Parses the buffer, for name-value pairs and creates nvlist. The value
+ * is always considered to be a string.
+ */
+int
+ipadm_str2nvlist(const char *inbuf, nvlist_t **ipnvl, uint_t flags)
+{
+	char	*nv, *name, *val, *buf, *cp, *sep;
+	int	err;
+
+	if (inbuf == NULL || inbuf[0] == '\0' || ipnvl == NULL)
+		return (EINVAL);
+	*ipnvl = NULL;
+
+	/*
+	 * If IPADM_NORVAL is set, then `inbuf' should be comma delimited values
+	 */
+	if ((flags & IPADM_NORVAL) && strchr(inbuf, '=') != NULL)
+		return (EINVAL);
+
+	if ((cp = buf = strdup(inbuf)) == NULL)
+		return (errno);
+
+	while (isspace(*buf))
+		buf++;
+
+	if (*buf == '\0') {
+		err = EINVAL;
+		goto fail;
+	}
+
+	nv = buf;
+	/*
+	 * work on one nvpair at a time and extract the name and value
+	 */
+	sep = ((flags & IPADM_NORVAL) ? IPADM_NAME_SEP : IPADM_NVPAIR_SEP);
+	while ((nv = strsep(&buf, sep)) != NULL) {
+		if (*nv == '\n')
+			continue;
+		name = nv;
+		if ((val = strchr(nv, '=')) != NULL)
+			*val++ = '\0';
+		if (*ipnvl == NULL &&
+		    (err = nvlist_alloc(ipnvl, NV_UNIQUE_NAME, 0)) != 0)
+			goto fail;
+		if (nvlist_exists(*ipnvl, name)) {
+			err = EEXIST;
+			goto fail;
+		}
+		/* Add the extracted nvpair to the nvlist `ipnvl'. */
+		(void) i_ipadm_add_nvpair(*ipnvl, name, val);
+	}
+	free(cp);
+	return (0);
+fail:
+	free(cp);
+	nvlist_free(*ipnvl);
+	*ipnvl = NULL;
+	return (err);
+}
+
+/*
+ * Opens the data store for read/write operation. For write operation we open
+ * another file and scribble the changes to it and copy the new file back to
+ * old file.
+ */
+int
+ipadm_rw_db(db_wfunc_t *db_walk_func, void *arg, const char *db_file,
+    mode_t db_perms, ipadm_db_op_t db_op)
+{
+	FILE		*fp, *nfp = NULL;
+	char		file[MAXPATHLEN];
+	char		newfile[MAXPATHLEN];
+	int		nfd;
+	boolean_t	writeop;
+	int		err = 0;
+
+	writeop = (db_op != IPADM_DB_READ);
+
+	(void) snprintf(file, MAXPATHLEN, "%s/%s", ipadm_rootdir, db_file);
+
+	/* open the data store */
+	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL)
+		return (errno);
+
+	if (writeop) {
+		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
+		    ipadm_rootdir, db_file);
+		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
+		    db_perms)) < 0) {
+			err = errno;
+			(void) fclose(fp);
+			return (err);
+		}
+
+		if ((nfp = fdopen(nfd, "w")) == NULL) {
+			err = errno;
+			(void) close(nfd);
+			(void) fclose(fp);
+			(void) unlink(newfile);
+			return (err);
+		}
+	}
+	err = ipadm_process_db_line(db_walk_func, arg, fp, nfp, db_op);
+	if (!writeop)
+		goto done;
+	if (err != 0 && err != ENOENT)
+		goto done;
+
+	if (fflush(nfp) == EOF) {
+		err = errno;
+		goto done;
+	}
+	(void) fclose(fp);
+	(void) fclose(nfp);
+
+	if (rename(newfile, file) < 0) {
+		err = errno;
+		(void) unlink(newfile);
+	}
+	return (err);
+done:
+	if (nfp != NULL) {
+		(void) fclose(nfp);
+		if (err != 0)
+			(void) unlink(newfile);
+	}
+	(void) fclose(fp);
+	return (err);
+}
+
+/*
+ * Processes each line of the configuration file, skipping lines with
+ * leading spaces, blank lines and comments. The line form the DB
+ * is converted to nvlist and the callback function is called to process
+ * the list. The buf could be modified by the callback function and
+ * if this is a write operation and buf is not truncated, buf will
+ * be written to disk.
+ *
+ * Further if cont is set to B_FALSE,  the remainder of the file will
+ * continue to be read (however callback function will not be called) and,
+ * if necessary, written to disk as well.
+ */
+static int
+ipadm_process_db_line(db_wfunc_t *db_walk_func, void *arg, FILE *fp, FILE *nfp,
+    ipadm_db_op_t db_op)
+{
+	int		err = 0;
+	char		buf[MAXLINELEN];
+	boolean_t	cont = B_TRUE;
+	int		i, len;
+	nvlist_t	*db_nvl = NULL;
+	boolean_t	line_deleted = B_FALSE;
+
+	while (fgets(buf, MAXLINELEN, fp) != NULL) {
+		/*
+		 * Skip leading spaces, blank lines, and comments.
+		 */
+		len = strnlen(buf, MAXLINELEN);
+		for (i = 0; i < len; i++) {
+			if (!isspace(buf[i]))
+				break;
+		}
+
+		if (i != len && buf[i] != '#' && cont) {
+			if (ipadm_str2nvlist(buf, &db_nvl, 0) == 0) {
+				cont = db_walk_func(arg, db_nvl, buf,
+				    MAXLINELEN, &err);
+			} else {
+				/* Delete corrupted line. */
+				buf[0] = '\0';
+			}
+			nvlist_free(db_nvl);
+			db_nvl = NULL;
+		}
+		if (err != 0)
+			break;
+		if (nfp != NULL && buf[0] == '\0')
+			line_deleted = B_TRUE;
+		if (nfp != NULL	&& buf[0] != '\0' && fputs(buf, nfp) == EOF) {
+			err = errno;
+			break;
+		}
+	}
+
+	if (err != 0 || !cont)
+		return (err);
+
+	if (db_op == IPADM_DB_WRITE) {
+		ipadm_dbwrite_cbarg_t	*cb = arg;
+		nvlist_t		*nvl = cb->dbw_nvl;
+
+		/*
+		 * If the specified entry is not found above, we add
+		 * the entry to the configuration file, here.
+		 */
+		(void) memset(buf, 0, MAXLINELEN);
+		if (ipadm_nvlist2str(nvl, buf, MAXLINELEN) == 0)
+			err = ENOBUFS;
+		else if (fputs(buf, nfp) == EOF)
+			err = errno;
+		return (err);
+	}
+
+	if (db_op == IPADM_DB_DELETE && line_deleted)
+		return (0);
+
+	/* if we have come this far, then we didn't find any match */
+	return (ENOENT);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/ipadm_prop.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,1699 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file contains routines that are used to modify/retrieve protocol or
+ * interface property values. It also holds all the supported properties for
+ * both IP interface and protocols in `ipadm_prop_desc_t'. Following protocols
+ * are supported: IP, IPv4, IPv6, TCP, SCTP, UDP and ICMP.
+ *
+ * This file also contains walkers, which walks through the property table and
+ * calls the callback function, of the form `ipadm_prop_wfunc_t' , for every
+ * property in the table.
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/sockio.h>
+#include <assert.h>
+#include <libdllink.h>
+#include <zone.h>
+#include "libipadm_impl.h"
+
+#define	IPADM_NONESTR	"none"
+#define	DEF_METRIC_VAL	0	/* default metric value */
+
+#define	A_CNT(arr)	(sizeof (arr) / sizeof (arr[0]))
+
+static ipadm_status_t i_ipadm_validate_if(ipadm_handle_t, const char *,
+    uint_t, uint_t);
+
+/*
+ * Callback functions to retrieve property values from the kernel. These
+ * functions, when required, translate the values from the kernel to a format
+ * suitable for printing. For example: boolean values will be translated
+ * to on/off. They also retrieve DEFAULT, PERM and POSSIBLE values for
+ * a given property.
+ */
+static ipadm_pd_getf_t	i_ipadm_get_prop, i_ipadm_get_ifprop_flags,
+			i_ipadm_get_mtu, i_ipadm_get_metric,
+			i_ipadm_get_usesrc, i_ipadm_get_forwarding,
+			i_ipadm_get_ecnsack;
+
+/*
+ * Callback function to set property values. These functions translate the
+ * values to a format suitable for kernel consumption, allocates the necessary
+ * ioctl buffers and then invokes ioctl().
+ */
+static ipadm_pd_setf_t	i_ipadm_set_prop, i_ipadm_set_mtu,
+			i_ipadm_set_ifprop_flags,
+			i_ipadm_set_metric, i_ipadm_set_usesrc,
+			i_ipadm_set_forwarding, i_ipadm_set_eprivport,
+			i_ipadm_set_ecnsack;
+
+/* array of protocols we support */
+static int protocols[] = { MOD_PROTO_IP, MOD_PROTO_RAWIP,
+			    MOD_PROTO_TCP, MOD_PROTO_UDP,
+			    MOD_PROTO_SCTP };
+
+/*
+ * Supported IP protocol properties.
+ */
+static ipadm_prop_desc_t ipadm_ip_prop_table[] = {
+	{ "arp", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4,
+	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
+	    i_ipadm_get_ifprop_flags },
+
+	{ "forwarding", IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV4,
+	    i_ipadm_set_forwarding, i_ipadm_get_onoff,
+	    i_ipadm_get_forwarding },
+
+	{ "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4,
+	    i_ipadm_set_metric, NULL, i_ipadm_get_metric },
+
+	{ "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4,
+	    i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
+
+	{ "exchange_routes", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4,
+	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
+	    i_ipadm_get_ifprop_flags },
+
+	{ "usesrc", IPADMPROP_CLASS_IF, MOD_PROTO_IPV4,
+	    i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
+
+	{ "ttl", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV4,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "forwarding", IPADMPROP_CLASS_MODIF, MOD_PROTO_IPV6,
+	    i_ipadm_set_forwarding, i_ipadm_get_onoff,
+	    i_ipadm_get_forwarding },
+
+	{ "hoplimit", IPADMPROP_CLASS_MODULE, MOD_PROTO_IPV6,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "metric", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6,
+	    i_ipadm_set_metric, NULL, i_ipadm_get_metric },
+
+	{ "mtu", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6,
+	    i_ipadm_set_mtu, i_ipadm_get_mtu, i_ipadm_get_mtu },
+
+	{ "nud", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6,
+	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
+	    i_ipadm_get_ifprop_flags },
+
+	{ "exchange_routes", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6,
+	    i_ipadm_set_ifprop_flags, i_ipadm_get_onoff,
+	    i_ipadm_get_ifprop_flags },
+
+	{ "usesrc", IPADMPROP_CLASS_IF, MOD_PROTO_IPV6,
+	    i_ipadm_set_usesrc, NULL, i_ipadm_get_usesrc },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+/* possible values for TCP properties `ecn' and `sack' */
+static const char *ecn_sack_vals[] = {"never", "passive", "active", NULL};
+
+/* Supported TCP protocol properties */
+static ipadm_prop_desc_t ipadm_tcp_prop_table[] = {
+	{ "ecn", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
+
+	{ "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "sack", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_ecnsack, i_ipadm_get_ecnsack, i_ipadm_get_ecnsack },
+
+	{ "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_TCP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+/* Supported UDP protocol properties */
+static ipadm_prop_desc_t ipadm_udp_prop_table[] = {
+	{ "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_UDP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+/* Supported SCTP protocol properties */
+static ipadm_prop_desc_t ipadm_sctp_prop_table[] = {
+	{ "extra_priv_ports", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_eprivport, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "largest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_anon_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "smallest_nonpriv_port", IPADMPROP_CLASS_MODULE, MOD_PROTO_SCTP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+/* Supported ICMP protocol properties */
+static ipadm_prop_desc_t ipadm_icmp_prop_table[] = {
+	{ "recv_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ "send_maxbuf", IPADMPROP_CLASS_MODULE, MOD_PROTO_RAWIP,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop },
+
+	{ NULL, 0, 0, NULL, NULL, NULL }
+};
+
+/*
+ * A dummy private property structure, used while handling private
+ * protocol properties (properties not yet supported by libipadm).
+ */
+static ipadm_prop_desc_t	ipadm_privprop =\
+	{ NULL, IPADMPROP_CLASS_MODULE, MOD_PROTO_NONE,
+	    i_ipadm_set_prop, i_ipadm_get_prop, i_ipadm_get_prop };
+
+/*
+ * Returns the property description table, for the given protocol
+ */
+static ipadm_prop_desc_t *
+i_ipadm_get_propdesc_table(uint_t proto)
+{
+	switch (proto) {
+	case MOD_PROTO_IP:
+	case MOD_PROTO_IPV4:
+	case MOD_PROTO_IPV6:
+		return (ipadm_ip_prop_table);
+	case MOD_PROTO_RAWIP:
+		return (ipadm_icmp_prop_table);
+	case MOD_PROTO_TCP:
+		return (ipadm_tcp_prop_table);
+	case MOD_PROTO_UDP:
+		return (ipadm_udp_prop_table);
+	case MOD_PROTO_SCTP:
+		return (ipadm_sctp_prop_table);
+	}
+
+	return (NULL);
+}
+
+char *
+ipadm_proto2str(uint_t proto)
+{
+	switch (proto) {
+	case MOD_PROTO_IP:
+		return ("ip");
+	case MOD_PROTO_IPV4:
+		return ("ipv4");
+	case MOD_PROTO_IPV6:
+		return ("ipv6");
+	case MOD_PROTO_RAWIP:
+		return ("icmp");
+	case MOD_PROTO_TCP:
+		return ("tcp");
+	case MOD_PROTO_UDP:
+		return ("udp");
+	case MOD_PROTO_SCTP:
+		return ("sctp");
+	}
+
+	return (NULL);
+}
+
+uint_t
+ipadm_str2proto(const char *protostr)
+{
+	if (protostr == NULL)
+		return (MOD_PROTO_NONE);
+	if (strcmp(protostr, "tcp") == 0)
+		return (MOD_PROTO_TCP);
+	else if (strcmp(protostr, "udp") == 0)
+		return (MOD_PROTO_UDP);
+	else if (strcmp(protostr, "ip") == 0)
+		return (MOD_PROTO_IP);
+	else if (strcmp(protostr, "ipv4") == 0)
+		return (MOD_PROTO_IPV4);
+	else if (strcmp(protostr, "ipv6") == 0)
+		return (MOD_PROTO_IPV6);
+	else if (strcmp(protostr, "icmp") == 0)
+		return (MOD_PROTO_RAWIP);
+	else if (strcmp(protostr, "sctp") == 0)
+		return (MOD_PROTO_SCTP);
+	else if (strcmp(protostr, "arp") == 0)
+		return (MOD_PROTO_IP);
+
+	return (MOD_PROTO_NONE);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_mtu(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	struct lifreq	lifr;
+	char		*endp;
+	uint_t		mtu;
+	int		s;
+	const char	*ifname = arg;
+	char		val[MAXPROPVALLEN];
+
+	/* to reset MTU first retrieve the default MTU and then set it */
+	if (flags & IPADM_OPT_DEFAULT) {
+		ipadm_status_t	status;
+		uint_t		size = MAXPROPVALLEN;
+
+		status = i_ipadm_get_prop(iph, arg, pdp, val, &size,
+		    proto, MOD_PROP_DEFAULT);
+		if (status != IPADM_SUCCESS)
+			return (status);
+		pval = val;
+	}
+
+	errno = 0;
+	mtu = (uint_t)strtol(pval, &endp, 10);
+	if (errno != 0 || *endp != '\0')
+		return (IPADM_INVALID_ARG);
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	lifr.lifr_mtu = mtu;
+
+	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+	if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_metric(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	struct lifreq	lifr;
+	char		*endp;
+	int		metric;
+	const char	*ifname = arg;
+	int		s;
+
+	/* if we are resetting, set the value to its default value */
+	if (flags & IPADM_OPT_DEFAULT) {
+		metric = DEF_METRIC_VAL;
+	} else {
+		errno = 0;
+		metric = (uint_t)strtol(pval, &endp, 10);
+		if (errno != 0 || *endp != '\0')
+			return (IPADM_INVALID_ARG);
+	}
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	lifr.lifr_metric = metric;
+
+	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+
+	if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_usesrc(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	struct lifreq	lifr;
+	const char	*ifname = arg;
+	int		s;
+	uint_t		ifindex = 0;
+
+	/* if we are resetting, set the value to its default value */
+	if (flags & IPADM_OPT_DEFAULT)
+		pval = IPADM_NONESTR;
+
+	/*
+	 * cannot specify logical interface name. We can also filter out other
+	 * bogus interface names here itself through i_ipadm_validate_ifname().
+	 */
+	if (strcmp(pval, IPADM_NONESTR) != 0 &&
+	    !i_ipadm_validate_ifname(iph, pval))
+		return (IPADM_INVALID_ARG);
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+
+	s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+
+	if (strcmp(pval, IPADM_NONESTR) != 0) {
+		if ((ifindex = if_nametoindex(pval)) == 0)
+			return (ipadm_errno2status(errno));
+		lifr.lifr_index = ifindex;
+	} else {
+		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		lifr.lifr_index = 0;
+	}
+	if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_ifprop_flags(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	ipadm_status_t	status = IPADM_SUCCESS;
+	const char	*ifname = arg;
+	uint64_t	on_flags = 0, off_flags = 0;
+	boolean_t	on = B_FALSE;
+	sa_family_t	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
+
+	/* if we are resetting, set the value to its default value */
+	if (flags & IPADM_OPT_DEFAULT) {
+		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
+		    strcmp(pdp->ipd_name, "arp") == 0 ||
+		    strcmp(pdp->ipd_name, "nud") == 0) {
+			pval = IPADM_ONSTR;
+		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+			pval = IPADM_OFFSTR;
+		} else {
+			return (IPADM_PROP_UNKNOWN);
+		}
+	}
+
+	if (strcmp(pval, IPADM_ONSTR) == 0)
+		on = B_TRUE;
+	else if (strcmp(pval, IPADM_OFFSTR) == 0)
+		on = B_FALSE;
+	else
+		return (IPADM_INVALID_ARG);
+
+	if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
+		if (on)
+			off_flags = IFF_NORTEXCH;
+		else
+			on_flags = IFF_NORTEXCH;
+	} else if (strcmp(pdp->ipd_name, "arp") == 0) {
+		if (on)
+			off_flags = IFF_NOARP;
+		else
+			on_flags = IFF_NOARP;
+	} else if (strcmp(pdp->ipd_name, "nud") == 0) {
+		if (on)
+			off_flags = IFF_NONUD;
+		else
+			on_flags = IFF_NONUD;
+	} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+		if (on)
+			on_flags = IFF_ROUTER;
+		else
+			off_flags = IFF_ROUTER;
+	}
+
+	if (on_flags || off_flags)  {
+		status = i_ipadm_set_flags(iph, ifname, af, on_flags,
+		    off_flags);
+	}
+	return (status);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_eprivport(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	nvlist_t	*portsnvl = NULL;
+	nvpair_t	*nvp;
+	ipadm_status_t	status = IPADM_SUCCESS;
+	int		err;
+	char		*port;
+	uint_t		count = 0;
+
+	if (flags & IPADM_OPT_DEFAULT) {
+		assert(pval == NULL);
+		return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
+	}
+
+	if ((err = ipadm_str2nvlist(pval, &portsnvl, IPADM_NORVAL)) != 0)
+		return (ipadm_errno2status(err));
+
+	/* count the number of ports */
+	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
+		++count;
+	}
+
+	/* We allow only one port to be added or removed, at a time */
+	if (count > 1 && (flags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE)))
+		return (IPADM_INVALID_ARG);
+
+	/*
+	 * However on reboot, while initializing protocol properties,
+	 * extra_priv_ports might have multiple values. Only in that case
+	 * we allow setting multiple properties.
+	 */
+	if (count > 1 && !(iph->iph_flags & IPH_INIT))
+		return (IPADM_INVALID_ARG);
+
+	count = 0;
+	for (nvp = nvlist_next_nvpair(portsnvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(portsnvl, nvp)) {
+		port = nvpair_name(nvp);
+		if (count == 0) {
+			status = i_ipadm_set_prop(iph, arg, pdp, port, proto,
+			    flags);
+		} else {
+			assert(iph->iph_flags & IPH_INIT);
+			status = i_ipadm_set_prop(iph, arg, pdp, port, proto,
+			    IPADM_OPT_APPEND);
+		}
+		++count;
+		if (status != IPADM_SUCCESS)
+			break;
+	}
+ret:
+	nvlist_free(portsnvl);
+	return (status);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_forwarding(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	const char	*ifname = arg;
+	ipadm_status_t	status;
+
+	/*
+	 * if interface name is provided, then set forwarding using the
+	 * IFF_ROUTER flag
+	 */
+	if (ifname != NULL) {
+		status = i_ipadm_set_ifprop_flags(iph, ifname, pdp, pval,
+		    proto, flags);
+	} else {
+		char	*val = NULL;
+
+		/*
+		 * if the caller is IPH_LEGACY, `pval' already contains
+		 * numeric values.
+		 */
+		if (!(flags & IPADM_OPT_DEFAULT) &&
+		    !(iph->iph_flags & IPH_LEGACY)) {
+
+			if (strcmp(pval, IPADM_ONSTR) == 0)
+				val = "1";
+			else if (strcmp(pval, IPADM_OFFSTR) == 0)
+				val = "0";
+			else
+				return (IPADM_INVALID_ARG);
+			pval = val;
+		}
+
+		status = i_ipadm_set_prop(iph, ifname, pdp, pval, proto, flags);
+	}
+
+	return (status);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_set_ecnsack(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	uint_t		i;
+	char		val[MAXPROPVALLEN];
+
+	/* if IPH_LEGACY is set, `pval' already contains numeric values */
+	if (!(flags & IPADM_OPT_DEFAULT) && !(iph->iph_flags & IPH_LEGACY)) {
+		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
+			if (strcmp(pval, ecn_sack_vals[i]) == 0)
+				break;
+		}
+		if (ecn_sack_vals[i] == NULL)
+			return (IPADM_INVALID_ARG);
+		(void) snprintf(val, MAXPROPVALLEN, "%d", i);
+		pval = val;
+	}
+
+	return (i_ipadm_set_prop(iph, arg, pdp, pval, proto, flags));
+}
+
+/* ARGSUSED */
+ipadm_status_t
+i_ipadm_get_ecnsack(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	ipadm_status_t	status = IPADM_SUCCESS;
+	uint_t		i, nbytes = 0;
+
+	switch (valtype) {
+	case MOD_PROP_POSSIBLE:
+		for (i = 0; ecn_sack_vals[i] != NULL; i++) {
+			if (i == 0)
+				nbytes += snprintf(buf + nbytes,
+				    *bufsize - nbytes, "%s", ecn_sack_vals[i]);
+			else
+				nbytes += snprintf(buf + nbytes,
+				    *bufsize - nbytes, ",%s", ecn_sack_vals[i]);
+			if (nbytes >= *bufsize)
+				break;
+		}
+		break;
+	case MOD_PROP_PERM:
+	case MOD_PROP_DEFAULT:
+	case MOD_PROP_ACTIVE:
+		status = i_ipadm_get_prop(iph, arg, pdp, buf, bufsize, proto,
+		    valtype);
+
+		/*
+		 * If IPH_LEGACY is set, do not convert the value returned
+		 * from kernel,
+		 */
+		if (iph->iph_flags & IPH_LEGACY)
+			break;
+
+		/*
+		 * For current and default value, convert the value returned
+		 * from kernel to more discrete representation.
+		 */
+		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
+		    valtype == MOD_PROP_DEFAULT)) {
+			i = atoi(buf);
+			assert(i < 3);
+			nbytes = snprintf(buf, *bufsize, "%s",
+			    ecn_sack_vals[i]);
+		}
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+
+	return (status);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_forwarding(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	const char	*ifname = arg;
+	ipadm_status_t	status = IPADM_SUCCESS;
+
+	/*
+	 * if interface name is provided, then get forwarding status using
+	 * SIOCGLIFFLAGS
+	 */
+	if (ifname != NULL) {
+		status = i_ipadm_get_ifprop_flags(iph, ifname, pdp,
+		    buf, bufsize, pdp->ipd_proto, valtype);
+	} else {
+		status = i_ipadm_get_prop(iph, ifname, pdp, buf,
+		    bufsize, proto, valtype);
+		/*
+		 * If IPH_LEGACY is set, do not convert the value returned
+		 * from kernel,
+		 */
+		if (iph->iph_flags & IPH_LEGACY)
+			goto ret;
+		if (status == IPADM_SUCCESS && (valtype == MOD_PROP_ACTIVE ||
+		    valtype == MOD_PROP_DEFAULT)) {
+			uint_t	val = atoi(buf);
+
+			(void) snprintf(buf, *bufsize,
+			    (val == 1 ? IPADM_ONSTR : IPADM_OFFSTR));
+		}
+	}
+
+ret:
+	return (status);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_mtu(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	struct lifreq	lifr;
+	const char	*ifname = arg;
+	size_t		nbytes;
+	int		s;
+
+	switch (valtype) {
+	case MOD_PROP_PERM:
+		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
+		break;
+	case MOD_PROP_DEFAULT:
+	case MOD_PROP_POSSIBLE:
+		return (i_ipadm_get_prop(iph, arg, pdp, buf, bufsize,
+		    proto, valtype));
+	case MOD_PROP_ACTIVE:
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+
+		if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		nbytes = snprintf(buf, *bufsize, "%u", lifr.lifr_mtu);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_metric(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	struct lifreq	lifr;
+	const char	*ifname = arg;
+	size_t		nbytes;
+	int		s, val;
+
+	switch (valtype) {
+	case MOD_PROP_PERM:
+		val = MOD_PROP_PERM_RW;
+		break;
+	case MOD_PROP_DEFAULT:
+		val = DEF_METRIC_VAL;
+		break;
+	case MOD_PROP_ACTIVE:
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+
+		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+		if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		val = lifr.lifr_metric;
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	nbytes = snprintf(buf, *bufsize, "%d", val);
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_usesrc(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *ipd, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	struct lifreq	lifr;
+	const char	*ifname = arg;
+	int		s;
+	char 		if_name[IF_NAMESIZE];
+	size_t		nbytes;
+
+	switch (valtype) {
+	case MOD_PROP_PERM:
+		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
+		break;
+	case MOD_PROP_DEFAULT:
+		nbytes = snprintf(buf, *bufsize, "%s", IPADM_NONESTR);
+		break;
+	case MOD_PROP_ACTIVE:
+		bzero(&lifr, sizeof (lifr));
+		(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+
+		s = (proto == MOD_PROTO_IPV6 ? iph->iph_sock6 : iph->iph_sock);
+		if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) < 0)
+			return (ipadm_errno2status(errno));
+		if (lifr.lifr_index == 0) {
+			/* no src address was set, so print 'none' */
+			(void) strlcpy(if_name, IPADM_NONESTR,
+			    sizeof (if_name));
+		} else if (if_indextoname(lifr.lifr_index, if_name) == NULL) {
+			return (ipadm_errno2status(errno));
+		}
+		nbytes = snprintf(buf, *bufsize, "%s", if_name);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		return (IPADM_NO_BUFS);
+	}
+	return (IPADM_SUCCESS);
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_ifprop_flags(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	uint64_t 	intf_flags;
+	char 		*val;
+	size_t		nbytes;
+	const char	*ifname = arg;
+	sa_family_t	af;
+	ipadm_status_t	status = IPADM_SUCCESS;
+
+	switch (valtype) {
+	case MOD_PROP_PERM:
+		nbytes = snprintf(buf, *bufsize, "%d", MOD_PROP_PERM_RW);
+		break;
+	case MOD_PROP_DEFAULT:
+		if (strcmp(pdp->ipd_name, "exchange_routes") == 0 ||
+		    strcmp(pdp->ipd_name, "arp") == 0 ||
+		    strcmp(pdp->ipd_name, "nud") == 0) {
+			val = IPADM_ONSTR;
+		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+			val = IPADM_OFFSTR;
+		} else {
+			return (IPADM_PROP_UNKNOWN);
+		}
+		nbytes = snprintf(buf, *bufsize, "%s", val);
+		break;
+	case MOD_PROP_ACTIVE:
+		af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
+		status = i_ipadm_get_flags(iph, ifname, af, &intf_flags);
+		if (status != IPADM_SUCCESS)
+			return (status);
+
+		val = IPADM_OFFSTR;
+		if (strcmp(pdp->ipd_name, "exchange_routes") == 0) {
+			if (!(intf_flags & IFF_NORTEXCH))
+				val = IPADM_ONSTR;
+		} else if (strcmp(pdp->ipd_name, "forwarding") == 0) {
+			if (intf_flags & IFF_ROUTER)
+				val = IPADM_ONSTR;
+		} else if (strcmp(pdp->ipd_name, "arp") == 0) {
+			if (!(intf_flags & IFF_NOARP))
+				val = IPADM_ONSTR;
+		} else if (strcmp(pdp->ipd_name, "nud") == 0) {
+			if (!(intf_flags & IFF_NONUD))
+				val = IPADM_ONSTR;
+		}
+		nbytes = snprintf(buf, *bufsize, "%s", val);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+	if (nbytes >= *bufsize) {
+		/* insufficient buffer space */
+		*bufsize = nbytes + 1;
+		status = IPADM_NO_BUFS;
+	}
+
+	return (status);
+}
+
+static void
+i_ipadm_perm2str(char *buf, uint_t *bufsize)
+{
+	uint_t perm = atoi(buf);
+
+	(void) snprintf(buf, *bufsize, "%c%c",
+	    ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
+	    ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
+}
+
+/* ARGSUSED */
+static ipadm_status_t
+i_ipadm_get_prop(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	ipadm_status_t	status = IPADM_SUCCESS;
+	const char	*ifname = arg;
+	mod_ioc_prop_t	*mip;
+	char 		*pname = pdp->ipd_name;
+	uint_t		iocsize;
+
+	/* allocate sufficient ioctl buffer to retrieve value */
+	iocsize = sizeof (mod_ioc_prop_t) + *bufsize - 1;
+	if ((mip = calloc(1, iocsize)) == NULL)
+		return (IPADM_NO_BUFS);
+
+	mip->mpr_version = MOD_PROP_VERSION;
+	mip->mpr_flags = valtype;
+	mip->mpr_proto = proto;
+	if (ifname != NULL) {
+		(void) strlcpy(mip->mpr_ifname, ifname,
+		    sizeof (mip->mpr_ifname));
+	}
+	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
+	mip->mpr_valsize = *bufsize;
+
+	if (i_ipadm_strioctl(iph->iph_sock, SIOCGETPROP, (char *)mip,
+	    iocsize) < 0) {
+		if (errno == ENOENT)
+			status = IPADM_PROP_UNKNOWN;
+		else
+			status = ipadm_errno2status(errno);
+	} else {
+		bcopy(mip->mpr_val, buf, *bufsize);
+	}
+
+	free(mip);
+	return (status);
+}
+
+/*
+ * populates the ipmgmt_prop_arg_t based on the class of property.
+ */
+static void
+i_ipadm_populate_proparg(ipmgmt_prop_arg_t *pargp, ipadm_prop_desc_t *pdp,
+    const char *pval, const void *object)
+{
+	const struct ipadm_addrobj_s *ipaddr;
+	uint_t		class = pdp->ipd_class;
+	uint_t		proto = pdp->ipd_proto;
+
+	(void) strlcpy(pargp->ia_pname, pdp->ipd_name,
+	    sizeof (pargp->ia_pname));
+	if (pval != NULL)
+		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
+
+	switch (class) {
+	case IPADMPROP_CLASS_MODULE:
+		(void) strlcpy(pargp->ia_module, object,
+		    sizeof (pargp->ia_module));
+		break;
+	case IPADMPROP_CLASS_MODIF:
+		/* check if object is protostr or an ifname */
+		if (ipadm_str2proto(object) != MOD_PROTO_NONE) {
+			(void) strlcpy(pargp->ia_module, object,
+			    sizeof (pargp->ia_module));
+			break;
+		}
+		/* it's an interface property, fall through */
+		/* FALLTHRU */
+	case IPADMPROP_CLASS_IF:
+		(void) strlcpy(pargp->ia_ifname, object,
+		    sizeof (pargp->ia_ifname));
+		(void) strlcpy(pargp->ia_module, ipadm_proto2str(proto),
+		    sizeof (pargp->ia_module));
+		break;
+	case IPADMPROP_CLASS_ADDR:
+		ipaddr = object;
+		(void) strlcpy(pargp->ia_ifname, ipaddr->ipadm_ifname,
+		    sizeof (pargp->ia_ifname));
+		(void) strlcpy(pargp->ia_aobjname, ipaddr->ipadm_aobjname,
+		    sizeof (pargp->ia_aobjname));
+		break;
+	}
+}
+
+/*
+ * Common function to retrieve property value for a given interface `ifname' or
+ * for a given protocol `proto'. The property name is in `pname'.
+ *
+ * `valtype' determines the type of value that will be retrieved.
+ * 	IPADM_OPT_ACTIVE -	current value of the property (active config)
+ *	IPADM_OPT_PERSIST -	value of the property from persistent store
+ *	IPADM_OPT_DEFAULT -	default hard coded value (boot-time value)
+ *	IPADM_OPT_PERM -	read/write permissions for the value
+ *	IPADM_OPT_POSSIBLE -	range of values
+ */
+static ipadm_status_t
+i_ipadm_getprop_common(ipadm_handle_t iph, const char *ifname,
+    const char *pname, char *buf, uint_t *bufsize, uint_t proto,
+    uint_t valtype)
+{
+	ipadm_status_t		status = IPADM_SUCCESS;
+	ipadm_prop_desc_t	*pdp, *pdtbl;
+	char			priv_propname[MAXPROPNAMELEN];
+	boolean_t		matched_name = B_FALSE;
+	boolean_t		is_if = (ifname != NULL);
+
+	pdtbl = i_ipadm_get_propdesc_table(proto);
+
+	/*
+	 * We already checked for supported protocol,
+	 * pdtbl better not be NULL.
+	 */
+	assert(pdtbl != NULL);
+
+	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
+		if (strcmp(pname, pdp->ipd_name) == 0) {
+			matched_name = B_TRUE;
+			if (proto == pdp->ipd_proto)
+				break;
+		}
+	}
+
+	if (pdp->ipd_name != NULL) {
+		/*
+		 * check whether the property can be
+		 * applied on an interface
+		 */
+		if (is_if && !(pdp->ipd_class & IPADMPROP_CLASS_IF))
+			return (IPADM_INVALID_ARG);
+		/*
+		 * check whether the property can be
+		 * applied on a module
+		 */
+		if (!is_if && !(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
+			return (IPADM_INVALID_ARG);
+
+	} else {
+		/*
+		 * if we matched name, but failed protocol check,
+		 * then return error
+		 */
+		if (matched_name)
+			return (IPADM_INVALID_ARG);
+
+		/* there are no private interface properties */
+		if (is_if)
+			return (IPADM_PROP_UNKNOWN);
+
+		/* private protocol properties, pass it to kernel directly */
+		pdp = &ipadm_privprop;
+		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
+		pdp->ipd_name = priv_propname;
+	}
+
+	switch (valtype) {
+	case IPADM_OPT_PERM:
+		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
+		    MOD_PROP_PERM);
+		if (status == IPADM_SUCCESS)
+			i_ipadm_perm2str(buf, bufsize);
+		break;
+	case IPADM_OPT_ACTIVE:
+		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
+		    MOD_PROP_ACTIVE);
+		break;
+	case IPADM_OPT_DEFAULT:
+		status = pdp->ipd_get(iph, ifname, pdp, buf, bufsize, proto,
+		    MOD_PROP_DEFAULT);
+		break;
+	case IPADM_OPT_POSSIBLE:
+		if (pdp->ipd_get_range != NULL) {
+			status = pdp->ipd_get_range(iph, ifname, pdp, buf,
+			    bufsize, proto, MOD_PROP_POSSIBLE);
+			break;
+		}
+		buf[0] = '\0';
+		break;
+	case IPADM_OPT_PERSIST:
+		/* retrieve from database */
+		if (is_if)
+			status = i_ipadm_get_persist_propval(iph, pdp, buf,
+			    bufsize, ifname);
+		else
+			status = i_ipadm_get_persist_propval(iph, pdp, buf,
+			    bufsize, ipadm_proto2str(proto));
+		break;
+	default:
+		status = IPADM_INVALID_ARG;
+		break;
+	}
+	return (status);
+}
+
+/*
+ * Get protocol property of the specified protocol.
+ */
+ipadm_status_t
+ipadm_get_prop(ipadm_handle_t iph, const char *pname, char *buf,
+    uint_t *bufsize, uint_t proto, uint_t valtype)
+{
+	/*
+	 * validate the arguments of the function.
+	 */
+	if (iph == NULL || pname == NULL || buf == NULL ||
+	    bufsize == NULL || *bufsize == 0) {
+		return (IPADM_INVALID_ARG);
+	}
+	/*
+	 * Do we support this proto, if not return error.
+	 */
+	if (ipadm_proto2str(proto) == NULL)
+		return (IPADM_NOTSUP);
+
+	return (i_ipadm_getprop_common(iph, NULL, pname, buf, bufsize,
+	    proto, valtype));
+}
+
+/*
+ * Get interface property of the specified interface.
+ */
+ipadm_status_t
+ipadm_get_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
+    char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
+{
+	/* validate the arguments of the function. */
+	if (iph == NULL || pname == NULL || buf == NULL ||
+	    bufsize == NULL || *bufsize == 0) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/* Do we support this proto, if not return error. */
+	if (ipadm_proto2str(proto) == NULL)
+		return (IPADM_NOTSUP);
+
+	/*
+	 * check if interface name is provided for interface property and
+	 * is valid.
+	 */
+	if (!i_ipadm_validate_ifname(iph, ifname))
+		return (IPADM_INVALID_ARG);
+
+	return (i_ipadm_getprop_common(iph, ifname, pname, buf, bufsize,
+	    proto, valtype));
+}
+
+/*
+ * Allocates sufficient ioctl buffers and copies property name and the
+ * value, among other things. If the flag IPADM_OPT_DEFAULT is set, then
+ * `pval' will be NULL and it instructs the kernel to reset the current
+ * value to property's default value.
+ */
+static ipadm_status_t
+i_ipadm_set_prop(ipadm_handle_t iph, const void *arg,
+    ipadm_prop_desc_t *pdp, const void *pval, uint_t proto, uint_t flags)
+{
+	ipadm_status_t	status = IPADM_SUCCESS;
+	const char	*ifname = arg;
+	mod_ioc_prop_t 	*mip;
+	char 		*pname = pdp->ipd_name;
+	uint_t 		valsize, iocsize;
+	uint_t		iocflags = 0;
+
+	if (flags & IPADM_OPT_DEFAULT) {
+		iocflags |= MOD_PROP_DEFAULT;
+	} else if (flags & IPADM_OPT_ACTIVE) {
+		iocflags |= MOD_PROP_ACTIVE;
+		if (flags & IPADM_OPT_APPEND)
+			iocflags |= MOD_PROP_APPEND;
+		else if (flags & IPADM_OPT_REMOVE)
+			iocflags |= MOD_PROP_REMOVE;
+	}
+
+	if (pval != NULL) {
+		valsize = strlen(pval);
+		iocsize = sizeof (mod_ioc_prop_t) + valsize - 1;
+	} else {
+		valsize = 0;
+		iocsize = sizeof (mod_ioc_prop_t);
+	}
+
+	if ((mip = calloc(1, iocsize)) == NULL)
+		return (IPADM_NO_BUFS);
+
+	mip->mpr_version = MOD_PROP_VERSION;
+	mip->mpr_flags = iocflags;
+	mip->mpr_proto = proto;
+	if (ifname != NULL) {
+		(void) strlcpy(mip->mpr_ifname, ifname,
+		    sizeof (mip->mpr_ifname));
+	}
+
+	(void) strlcpy(mip->mpr_name, pname, sizeof (mip->mpr_name));
+	mip->mpr_valsize = valsize;
+	if (pval != NULL)
+		bcopy(pval, mip->mpr_val, valsize);
+
+	if (i_ipadm_strioctl(iph->iph_sock, SIOCSETPROP, (char *)mip,
+	    iocsize) < 0) {
+		if (errno == ENOENT)
+			status = IPADM_PROP_UNKNOWN;
+		else
+			status = ipadm_errno2status(errno);
+	}
+	free(mip);
+	return (status);
+}
+
+/*
+ * Common function for modifying both protocol/interface property.
+ *
+ * If:
+ *   IPADM_OPT_PERSIST is set then the value is persisted.
+ *   IPADM_OPT_DEFAULT is set then the default value for the property will
+ *		       be applied.
+ */
+static ipadm_status_t
+i_ipadm_setprop_common(ipadm_handle_t iph, const char *ifname,
+    const char *pname, const char *buf, uint_t proto, uint_t pflags)
+{
+	ipadm_status_t		status = IPADM_SUCCESS;
+	boolean_t 		persist = (pflags & IPADM_OPT_PERSIST);
+	boolean_t		reset = (pflags & IPADM_OPT_DEFAULT);
+	ipadm_prop_desc_t	*pdp, *pdtbl;
+	boolean_t		is_if = (ifname != NULL);
+	char			priv_propname[MAXPROPNAMELEN];
+	boolean_t		matched_name = B_FALSE;
+
+	/* Check that property value is within the allowed size */
+	if (!reset && strnlen(buf, MAXPROPVALLEN) >= MAXPROPVALLEN)
+		return (IPADM_INVALID_ARG);
+
+	pdtbl = i_ipadm_get_propdesc_table(proto);
+	/*
+	 * We already checked for supported protocol,
+	 * pdtbl better not be NULL.
+	 */
+	assert(pdtbl != NULL);
+
+	/* Walk through the property table to match the given property name */
+	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
+		/*
+		 * we find the entry which matches <pname, proto> tuple
+		 */
+		if (strcmp(pname, pdp->ipd_name) == 0) {
+			matched_name = B_TRUE;
+			if (pdp->ipd_proto == proto)
+				break;
+		}
+	}
+
+	if (pdp->ipd_name != NULL) {
+		/* do some sanity checks */
+		if (is_if) {
+			if (!(pdp->ipd_class & IPADMPROP_CLASS_IF))
+				return (IPADM_INVALID_ARG);
+		} else {
+			if (!(pdp->ipd_class & IPADMPROP_CLASS_MODULE))
+				return (IPADM_INVALID_ARG);
+		}
+	} else {
+		/*
+		 * if we matched name, but failed protocol check,
+		 * then return error.
+		 */
+		if (matched_name)
+			return (IPADM_BAD_PROTOCOL);
+
+		/* Possibly a private property, pass it to kernel directly */
+
+		/* there are no private interface properties */
+		if (is_if)
+			return (IPADM_PROP_UNKNOWN);
+
+		pdp = &ipadm_privprop;
+		(void) strlcpy(priv_propname, pname, sizeof (priv_propname));
+		pdp->ipd_name = priv_propname;
+	}
+
+	status = pdp->ipd_set(iph, ifname, pdp, buf, proto, pflags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	if (persist) {
+		if (is_if)
+			status = i_ipadm_persist_propval(iph, pdp, buf, ifname,
+			    pflags);
+		else
+			status = i_ipadm_persist_propval(iph, pdp, buf,
+			    ipadm_proto2str(proto), pflags);
+	}
+	return (status);
+}
+
+/*
+ * Sets the property value of the specified interface
+ */
+ipadm_status_t
+ipadm_set_ifprop(ipadm_handle_t iph, const char *ifname, const char *pname,
+    const char *buf, uint_t proto, uint_t pflags)
+{
+	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
+	ipadm_status_t	status;
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+	/*
+	 * validate the arguments of the function.
+	 */
+	if (iph == NULL || pname == NULL || (!reset && buf == NULL) ||
+	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
+	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT))) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/*
+	 * Do we support this protocol, if not return error.
+	 */
+	if (ipadm_proto2str(proto) == NULL)
+		return (IPADM_NOTSUP);
+
+	/*
+	 * Validate the interface and check if a persistent
+	 * operation is performed on a temporary object.
+	 */
+	status = i_ipadm_validate_if(iph, ifname, proto, pflags);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	return (i_ipadm_setprop_common(iph, ifname, pname, buf, proto,
+	    pflags));
+}
+
+/*
+ * Sets the property value of the specified protocol.
+ */
+ipadm_status_t
+ipadm_set_prop(ipadm_handle_t iph, const char *pname, const char *buf,
+    uint_t proto, uint_t pflags)
+{
+	boolean_t	reset = (pflags & IPADM_OPT_DEFAULT);
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+	/*
+	 * validate the arguments of the function.
+	 */
+	if (iph == NULL || pname == NULL ||(!reset && buf == NULL) ||
+	    pflags == 0 || pflags == IPADM_OPT_PERSIST ||
+	    (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT|
+	    IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
+		return (IPADM_INVALID_ARG);
+	}
+
+	/*
+	 * Do we support this proto, if not return error.
+	 */
+	if (ipadm_proto2str(proto) == NULL)
+		return (IPADM_NOTSUP);
+
+	return (i_ipadm_setprop_common(iph, NULL, pname, buf, proto,
+	    pflags));
+}
+
+/* helper function for ipadm_walk_proptbl */
+static void
+i_ipadm_walk_proptbl(ipadm_prop_desc_t *pdtbl, uint_t proto, uint_t class,
+    ipadm_prop_wfunc_t *func, void *arg)
+{
+	ipadm_prop_desc_t	*pdp;
+
+	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
+		if (!(pdp->ipd_class & class))
+			continue;
+
+		if (proto != MOD_PROTO_NONE && !(pdp->ipd_proto & proto))
+			continue;
+
+		/*
+		 * we found a class specific match, call the
+		 * user callback function.
+		 */
+		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
+			break;
+	}
+}
+
+/*
+ * Walks through all the properties, for a given protocol and property class
+ * (protocol or interface).
+ *
+ * Further if proto == MOD_PROTO_NONE, then it walks through all the supported
+ * protocol property tables.
+ */
+ipadm_status_t
+ipadm_walk_proptbl(uint_t proto, uint_t class, ipadm_prop_wfunc_t *func,
+    void *arg)
+{
+	ipadm_prop_desc_t	*pdtbl;
+	ipadm_status_t		status = IPADM_SUCCESS;
+	int			i;
+	int			count = A_CNT(protocols);
+
+	if (func == NULL)
+		return (IPADM_INVALID_ARG);
+
+	switch (class) {
+	case IPADMPROP_CLASS_ADDR:
+		pdtbl = ipadm_addrprop_table;
+		break;
+	case IPADMPROP_CLASS_IF:
+	case IPADMPROP_CLASS_MODULE:
+		pdtbl = i_ipadm_get_propdesc_table(proto);
+		if (pdtbl == NULL && proto != MOD_PROTO_NONE)
+			return (IPADM_INVALID_ARG);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+
+	if (pdtbl != NULL) {
+		/*
+		 * proto will be MOD_PROTO_NONE in the case of
+		 * IPADMPROP_CLASS_ADDR.
+		 */
+		i_ipadm_walk_proptbl(pdtbl, proto, class, func, arg);
+	} else {
+		/* Walk thru all the protocol tables, we support */
+		for (i = 0; i < count; i++) {
+			pdtbl = i_ipadm_get_propdesc_table(protocols[i]);
+			i_ipadm_walk_proptbl(pdtbl, protocols[i], class, func,
+			    arg);
+		}
+	}
+	return (status);
+}
+
+/*
+ * Given a property name, walks through all the instances of a property name.
+ * Some properties have two instances one for v4 interfaces and another for v6
+ * interfaces. For example: MTU. MTU can have different values for v4 and v6.
+ * Therefore there are two properties for 'MTU'.
+ *
+ * This function invokes `func' for every instance of property `pname'
+ */
+ipadm_status_t
+ipadm_walk_prop(const char *pname, uint_t proto, uint_t class,
+    ipadm_prop_wfunc_t *func, void *arg)
+{
+	ipadm_prop_desc_t	*pdtbl, *pdp;
+	ipadm_status_t		status = IPADM_SUCCESS;
+	boolean_t		matched = B_FALSE;
+
+	if (pname == NULL || func == NULL)
+		return (IPADM_INVALID_ARG);
+
+	switch (class) {
+	case IPADMPROP_CLASS_ADDR:
+		pdtbl = ipadm_addrprop_table;
+		break;
+	case IPADMPROP_CLASS_IF:
+	case IPADMPROP_CLASS_MODULE:
+		pdtbl = i_ipadm_get_propdesc_table(proto);
+		break;
+	default:
+		return (IPADM_INVALID_ARG);
+	}
+
+	if (pdtbl == NULL)
+		return (IPADM_INVALID_ARG);
+
+	for (pdp = pdtbl; pdp->ipd_name != NULL; pdp++) {
+		if (strcmp(pname, pdp->ipd_name) != 0)
+			continue;
+		if (!(pdp->ipd_proto & proto))
+			continue;
+		matched = B_TRUE;
+		/* we found a match, call the callback function */
+		if (func(arg, pdp->ipd_name, pdp->ipd_proto) == B_FALSE)
+			break;
+	}
+	if (!matched)
+		status = IPADM_PROP_UNKNOWN;
+	return (status);
+}
+
+/* ARGSUSED */
+ipadm_status_t
+i_ipadm_get_onoff(ipadm_handle_t iph, const void *arg, ipadm_prop_desc_t *dp,
+    char *buf, uint_t *bufsize, uint_t proto, uint_t valtype)
+{
+	(void) snprintf(buf, *bufsize, "%s,%s", IPADM_ONSTR, IPADM_OFFSTR);
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Makes a door call to ipmgmtd to retrieve the persisted property value
+ */
+ipadm_status_t
+i_ipadm_get_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
+    char *gbuf, uint_t *gbufsize, const void *object)
+{
+	ipmgmt_prop_arg_t	parg;
+	ipmgmt_getprop_rval_t	rval, *rvalp;
+	size_t			nbytes;
+	int			err = 0;
+
+	bzero(&parg, sizeof (parg));
+	parg.ia_cmd = IPMGMT_CMD_GETPROP;
+	i_ipadm_populate_proparg(&parg, pdp, NULL, object);
+
+	rvalp = &rval;
+	err = ipadm_door_call(iph, &parg, sizeof (parg), (void **)&rvalp,
+	    sizeof (rval), B_FALSE);
+	if (err == 0) {
+		/* assert that rvalp was not reallocated */
+		assert(rvalp == &rval);
+
+		/* `ir_pval' contains the property value */
+		nbytes = snprintf(gbuf, *gbufsize, "%s", rvalp->ir_pval);
+		if (nbytes >= *gbufsize) {
+			/* insufficient buffer space */
+			*gbufsize = nbytes + 1;
+			err = ENOBUFS;
+		}
+	}
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Persists the property value for a given property in the data store
+ */
+ipadm_status_t
+i_ipadm_persist_propval(ipadm_handle_t iph, ipadm_prop_desc_t *pdp,
+    const char *pval, const void *object, uint_t flags)
+{
+	ipmgmt_prop_arg_t	parg;
+	int			err = 0;
+
+	bzero(&parg, sizeof (parg));
+	i_ipadm_populate_proparg(&parg, pdp, pval, object);
+
+	/*
+	 * Check if value to be persisted need to be appended or removed. This
+	 * is required for multi-valued property.
+	 */
+	if (flags & IPADM_OPT_APPEND)
+		parg.ia_flags |= IPMGMT_APPEND;
+	if (flags & IPADM_OPT_REMOVE)
+		parg.ia_flags |= IPMGMT_REMOVE;
+
+	if (flags & (IPADM_OPT_DEFAULT|IPADM_OPT_REMOVE))
+		parg.ia_cmd = IPMGMT_CMD_RESETPROP;
+	else
+		parg.ia_cmd = IPMGMT_CMD_SETPROP;
+
+	err = ipadm_door_call(iph, &parg, sizeof (parg), NULL, 0, B_FALSE);
+
+	/*
+	 * its fine if there were no entry in the DB to delete. The user
+	 * might be changing property value, which was not changed
+	 * persistently.
+	 */
+	if (err == ENOENT)
+		err = 0;
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * Called during boot.
+ *
+ * Walk through the DB and apply all the global module properties. We plow
+ * through the DB even if we fail to apply property.
+ */
+/* ARGSUSED */
+boolean_t
+ipadm_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
+    int *errp)
+{
+	ipadm_handle_t	iph = cbarg;
+	nvpair_t	*nvp, *pnvp;
+	char		*strval = NULL, *name, *mod = NULL;
+	uint_t		proto;
+
+	/*
+	 * We could have used nvl_exists() directly, however we need several
+	 * calls to it and each call traverses the list. Since this codepath
+	 * is exercised during boot, let's traverse the list ourselves and do
+	 * the necessary checks.
+	 */
+	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (IPADM_PRIV_NVP(name)) {
+			if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
+			    strcmp(name, IPADM_NVP_AOBJNAME) == 0)
+				return (B_TRUE);
+			else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
+			    nvpair_value_string(nvp, &mod) != 0)
+				return (B_TRUE);
+		} else {
+			/* possible a property */
+			pnvp = nvp;
+		}
+	}
+
+	/* if we are here than we found a global property */
+	assert(mod != NULL);
+	assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
+
+	proto = ipadm_str2proto(mod);
+	if (nvpair_value_string(pnvp, &strval) == 0) {
+		(void) ipadm_set_prop(iph, name, strval, proto,
+		    IPADM_OPT_ACTIVE);
+	}
+
+	return (B_TRUE);
+}
+
+/* initialize global module properties */
+ipadm_status_t
+ipadm_init_prop()
+{
+	ipadm_handle_t	iph = NULL;
+	ipadm_status_t	status;
+	int		err;
+
+	/* check for solaris.network.interface.config authorization */
+	if (!ipadm_check_auth())
+		return (IPADM_EAUTH);
+
+	if ((status = ipadm_open(&iph, IPH_INIT)) != IPADM_SUCCESS)
+		return (status);
+
+	err = ipadm_rw_db(ipadm_db_init, iph, IPADM_DB_FILE, IPADM_FILE_MODE,
+	    IPADM_DB_READ);
+
+	ipadm_close(iph);
+	return (ipadm_errno2status(err));
+}
+
+/*
+ * This is called from ipadm_set_ifprop() to validate the set operation.
+ * It does the following steps:
+ * 1. Validates the interface name.
+ * 2. Fails if it is an IPMP meta-interface or an underlying interface.
+ * 3. In case of a persistent operation, verifies that the
+ *	interface is persistent.
+ */
+static ipadm_status_t
+i_ipadm_validate_if(ipadm_handle_t iph, const char *ifname,
+    uint_t proto, uint_t flags)
+{
+	sa_family_t	af, other_af;
+	ipadm_status_t	status;
+	boolean_t	p_exists;
+	boolean_t	af_exists, other_af_exists, a_exists;
+
+	/* Check if the interface name is valid. */
+	if (!i_ipadm_validate_ifname(iph, ifname))
+		return (IPADM_INVALID_ARG);
+
+	af = (proto == MOD_PROTO_IPV6 ? AF_INET6 : AF_INET);
+	/*
+	 * Setting properties on an IPMP meta-interface or underlying
+	 * interface is not supported.
+	 */
+	if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
+		return (IPADM_NOTSUP);
+
+	/* Check if interface exists in the persistent configuration. */
+	status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
+	if (status != IPADM_SUCCESS)
+		return (status);
+
+	/* Check if interface exists in the active configuration. */
+	af_exists = ipadm_if_enabled(iph, ifname, af);
+	other_af = (af == AF_INET ? AF_INET6 : AF_INET);
+	other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
+	a_exists = (af_exists || other_af_exists);
+	if (!a_exists && p_exists)
+		return (IPADM_OP_DISABLE_OBJ);
+	if (!af_exists)
+		return (IPADM_ENXIO);
+
+	/*
+	 * If a persistent operation is requested, check if the underlying
+	 * IP interface is persistent.
+	 */
+	if ((flags & IPADM_OPT_PERSIST) && !p_exists)
+		return (IPADM_TEMPORARY_OBJ);
+	return (IPADM_SUCCESS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/libipadm.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,922 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <inet/ip.h>
+#include <arpa/inet.h>
+#include <libintl.h>
+#include <libdlpi.h>
+#include <libinetutil.h>
+#include <libdladm.h>
+#include <libdllink.h>
+#include <libdliptun.h>
+#include <strings.h>
+#include <zone.h>
+#include <ctype.h>
+#include <limits.h>
+#include <assert.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <auth_attr.h>
+#include <secdb.h>
+#include <nss_dbdefs.h>
+#include "libipadm_impl.h"
+
+/* error codes and text description */
+static struct ipadm_error_info {
+	ipadm_status_t	error_code;
+	const char	*error_desc;
+} ipadm_errors[] = {
+	{ IPADM_SUCCESS,	"Operation succeeded" },
+	{ IPADM_FAILURE,	"Operation failed" },
+	{ IPADM_EAUTH,		"Insufficient user authorizations" },
+	{ IPADM_EPERM,		"Permission denied" },
+	{ IPADM_NO_BUFS,	"No buffer space available" },
+	{ IPADM_NO_MEMORY,	"Insufficient memory" },
+	{ IPADM_BAD_ADDR,	"Invalid address" },
+	{ IPADM_BAD_PROTOCOL,	"Incorrect protocol family for operation" },
+	{ IPADM_DAD_FOUND,	"Duplicate address detected" },
+	{ IPADM_EXISTS,		"Already exists" },
+	{ IPADM_IF_EXISTS,	"Interface already exists" },
+	{ IPADM_ADDROBJ_EXISTS, "Address object already exists" },
+	{ IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
+	{ IPADM_ENXIO,		"Interface does not exist" },
+	{ IPADM_GRP_NOTEMPTY,	"IPMP group is not empty" },
+	{ IPADM_INVALID_ARG,	"Invalid argument provided" },
+	{ IPADM_INVALID_NAME,	"Invalid name" },
+	{ IPADM_DLPI_FAILURE,	"Could not open DLPI link" },
+	{ IPADM_DLADM_FAILURE,	"Datalink does not exist" },
+	{ IPADM_PROP_UNKNOWN,   "Unknown property" },
+	{ IPADM_ERANGE,		"Value is outside the allowed range" },
+	{ IPADM_ESRCH,		"Value does not exist" },
+	{ IPADM_EOVERFLOW,	"Number of values exceeds the allowed limit" },
+	{ IPADM_NOTFOUND,	"Object not found" },
+	{ IPADM_IF_INUSE,	"Interface already in use" },
+	{ IPADM_ADDR_INUSE,	"Address already in use" },
+	{ IPADM_BAD_HOSTNAME,	"Hostname maps to multiple IP addresses" },
+	{ IPADM_ADDR_NOTAVAIL,	"Can't assign requested address" },
+	{ IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
+	{ IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
+	{ IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
+	{ IPADM_DHCP_IPC_ERROR,	"Could not communicate with dhcpagent" },
+	{ IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
+	{ IPADM_TEMPORARY_OBJ,	"Persistent operation on temporary object" },
+	{ IPADM_IPC_ERROR,	"Could not communicate with ipmgmtd" },
+	{ IPADM_NOTSUP,		"Operation not supported" },
+	{ IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
+	{ IPADM_EBADE,		"Invalid data exchange with daemon" }
+};
+
+#define	IPADM_NUM_ERRORS	(sizeof (ipadm_errors) / sizeof (*ipadm_errors))
+
+ipadm_status_t
+ipadm_errno2status(int error)
+{
+	switch (error) {
+	case 0:
+		return (IPADM_SUCCESS);
+	case ENXIO:
+		return (IPADM_ENXIO);
+	case ENOMEM:
+		return (IPADM_NO_MEMORY);
+	case ENOBUFS:
+		return (IPADM_NO_BUFS);
+	case EINVAL:
+		return (IPADM_INVALID_ARG);
+	case EBUSY:
+		return (IPADM_IF_INUSE);
+	case EEXIST:
+		return (IPADM_EXISTS);
+	case EADDRNOTAVAIL:
+		return (IPADM_ADDR_NOTAVAIL);
+	case EADDRINUSE:
+		return (IPADM_ADDR_INUSE);
+	case ENOENT:
+		return (IPADM_NOTFOUND);
+	case ERANGE:
+		return (IPADM_ERANGE);
+	case EPERM:
+		return (IPADM_EPERM);
+	case ENOTSUP:
+	case EOPNOTSUPP:
+		return (IPADM_NOTSUP);
+	case EBADF:
+		return (IPADM_IPC_ERROR);
+	case EBADE:
+		return (IPADM_EBADE);
+	case ESRCH:
+		return (IPADM_ESRCH);
+	case EOVERFLOW:
+		return (IPADM_EOVERFLOW);
+	default:
+		return (IPADM_FAILURE);
+	}
+}
+
+/*
+ * Returns a message string for the given libipadm error status.
+ */
+const char *
+ipadm_status2str(ipadm_status_t status)
+{
+	int	i;
+
+	for (i = 0; i < IPADM_NUM_ERRORS; i++) {
+		if (status == ipadm_errors[i].error_code)
+			return (dgettext(TEXT_DOMAIN,
+			    ipadm_errors[i].error_desc));
+	}
+
+	return (dgettext(TEXT_DOMAIN, "<unknown error>"));
+}
+
+/*
+ * Opens a handle to libipadm.
+ * Possible values for flags:
+ *  IPH_VRRP:	Used by VRRP daemon to set the socket option SO_VRRP.
+ *  IPH_LEGACY:	This is used whenever an application needs to provide a
+ *		logical interface name while creating or deleting
+ *		interfaces and static addresses.
+ *  IPH_INIT:   Used by ipadm_init_prop(), to initialize protocol properties
+ *		on reboot.
+ */
+ipadm_status_t
+ipadm_open(ipadm_handle_t *handle, uint32_t flags)
+{
+	ipadm_handle_t	iph;
+	ipadm_status_t	status = IPADM_SUCCESS;
+	zoneid_t	zoneid;
+	ushort_t	zflags;
+	int		on = B_TRUE;
+
+	if (handle == NULL)
+		return (IPADM_INVALID_ARG);
+	*handle = NULL;
+
+	if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT))
+		return (IPADM_INVALID_ARG);
+
+	if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
+		return (IPADM_NO_MEMORY);
+	iph->iph_sock = -1;
+	iph->iph_sock6 = -1;
+	iph->iph_door_fd = -1;
+	iph->iph_flags = flags;
+	(void) pthread_mutex_init(&iph->iph_lock, NULL);
+
+	if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
+	    (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+		goto errnofail;
+	}
+
+	/*
+	 * We open a handle to libdladm here, to facilitate some daemons (like
+	 * nwamd) which opens handle to libipadm before devfsadmd installs the
+	 * right device permissions into the kernel and requires "all"
+	 * privileges to open DLD_CONTROL_DEV.
+	 *
+	 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
+	 * and dladm_open() will fail. So, we avoid this by not calling
+	 * dladm_open() for such zones.
+	 */
+	zoneid = getzoneid();
+	if (zoneid != GLOBAL_ZONEID) {
+		if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
+		    sizeof (zflags)) < 0) {
+			goto errnofail;
+		}
+	}
+	if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
+		if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
+			ipadm_close(iph);
+			return (IPADM_DLADM_FAILURE);
+		}
+	} else {
+		assert(zoneid != GLOBAL_ZONEID);
+		iph->iph_dlh = NULL;
+	}
+	if (flags & IPH_VRRP) {
+		if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
+		    sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
+		    SO_VRRP, &on, sizeof (on)) < 0) {
+			goto errnofail;
+		}
+	}
+	*handle = iph;
+	return (status);
+
+errnofail:
+	status = ipadm_errno2status(errno);
+	ipadm_close(iph);
+	return (status);
+}
+
+/*
+ * Closes and frees the libipadm handle.
+ */
+void
+ipadm_close(ipadm_handle_t iph)
+{
+	if (iph == NULL)
+		return;
+	if (iph->iph_sock != -1)
+		(void) close(iph->iph_sock);
+	if (iph->iph_sock6 != -1)
+		(void) close(iph->iph_sock6);
+	if (iph->iph_door_fd != -1)
+		(void) close(iph->iph_door_fd);
+	dladm_close(iph->iph_dlh);
+	(void) pthread_mutex_destroy(&iph->iph_lock);
+	free(iph);
+}
+
+/*
+ * Checks if the caller has the authorization to configure network
+ * interfaces.
+ */
+boolean_t
+ipadm_check_auth(void)
+{
+	struct passwd	pwd;
+	char		buf[NSS_BUFLEN_PASSWD];
+
+	/* get the password entry for the given user ID */
+	if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
+		return (B_FALSE);
+
+	/* check for presence of given authorization */
+	return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
+}
+
+/*
+ * Stores the index value of the interface in `ifname' for the address
+ * family `af' into the buffer pointed to by `index'.
+ */
+static ipadm_status_t
+i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
+    int *index)
+{
+	struct lifreq	lifr;
+	int		sock;
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (af == AF_INET)
+		sock = iph->iph_sock;
+	else
+		sock = iph->iph_sock6;
+
+	if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
+		return (ipadm_errno2status(errno));
+	*index = lifr.lifr_index;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Maximum amount of time (in milliseconds) to wait for Duplicate Address
+ * Detection to complete in the kernel.
+ */
+#define	DAD_WAIT_TIME		1000
+
+/*
+ * Any time that flags are changed on an interface where either the new or the
+ * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
+ * announce the new address added and its flag status.
+ * We wait here for that message and look for IFF_UP.
+ * If something's amiss with the kernel, though, we don't wait forever.
+ * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
+ * it in the routing socket messages.)
+ */
+static ipadm_status_t
+i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
+    int rtsock)
+{
+	struct pollfd	fds[1];
+	union {
+		struct if_msghdr ifm;
+		char buf[1024];
+	} msg;
+	int		index;
+	ipadm_status_t	retv;
+	uint64_t	flags;
+	hrtime_t	starttime, now;
+
+	fds[0].fd = rtsock;
+	fds[0].events = POLLIN;
+	fds[0].revents = 0;
+
+	retv = i_ipadm_get_index(handle, lifname, af, &index);
+	if (retv != IPADM_SUCCESS)
+		return (retv);
+
+	starttime = gethrtime();
+	for (;;) {
+		now = gethrtime();
+		now = (now - starttime) / 1000000;
+		if (now >= DAD_WAIT_TIME)
+			break;
+		if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
+			break;
+		if (read(rtsock, &msg, sizeof (msg)) <= 0)
+			break;
+		if (msg.ifm.ifm_type != RTM_NEWADDR)
+			continue;
+		/* Note that ifm_index is just 16 bits */
+		if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
+			return (IPADM_SUCCESS);
+	}
+
+	retv = i_ipadm_get_flags(handle, lifname, af, &flags);
+	if (retv != IPADM_SUCCESS)
+		return (retv);
+	if (flags & IFF_DUPLICATE)
+		return (IPADM_DAD_FOUND);
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
+ * interface in `lifname'.
+ *
+ * If the new flags value will transition the interface from "down" to "up"
+ * then duplicate address detection is performed by the kernel.  This routine
+ * waits to get the outcome of that test.
+ */
+ipadm_status_t
+i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
+    uint64_t on_flags, uint64_t off_flags)
+{
+	struct lifreq	lifr;
+	uint64_t	oflags;
+	ipadm_status_t	ret;
+	int		rtsock = -1;
+	int		sock, err;
+
+	ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
+	if (ret != IPADM_SUCCESS)
+		return (ret);
+
+	sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
+
+	/*
+	 * Any time flags are changed on an interface that has IFF_UP set,
+	 * we get a routing socket message.  We care about the status,
+	 * though, only when the new flags are marked "up."
+	 */
+	if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
+		rtsock = socket(PF_ROUTE, SOCK_RAW, af);
+
+	oflags |= on_flags;
+	oflags &= ~off_flags;
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
+	lifr.lifr_flags = oflags;
+	if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
+		err = errno;
+		if (rtsock != -1)
+			(void) close(rtsock);
+		return (ipadm_errno2status(err));
+	}
+	if (rtsock == -1) {
+		return (IPADM_SUCCESS);
+	} else {
+		/* Wait for DAD to complete. */
+		ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
+		(void) close(rtsock);
+		return (ret);
+	}
+}
+
+/*
+ * Returns the flags value for the logical interface in `lifname'
+ * in the buffer pointed to by `flags'.
+ */
+ipadm_status_t
+i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
+    uint64_t *flags)
+{
+	struct lifreq	lifr;
+	int		sock;
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
+	if (af == AF_INET)
+		sock = iph->iph_sock;
+	else
+		sock = iph->iph_sock6;
+
+	if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
+		return (ipadm_errno2status(errno));
+	}
+	*flags = lifr.lifr_flags;
+
+	return (IPADM_SUCCESS);
+}
+
+/*
+ * Determines whether or not an interface name represents a loopback
+ * interface, before the interface has been plumbed.
+ * It is assumed that the interface name in `ifname' is of correct format
+ * as verified by ifparse_ifspec().
+ *
+ * Returns: B_TRUE if loopback, B_FALSE if not.
+ */
+boolean_t
+i_ipadm_is_loopback(const char *ifname)
+{
+	int len = strlen(LOOPBACK_IF);
+
+	return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
+	    (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
+}
+
+/*
+ * Determines whether or not an interface name represents a vni
+ * interface, before the interface has been plumbed.
+ * It is assumed that the interface name in `ifname' is of correct format
+ * as verified by ifparse_ifspec().
+ *
+ * Returns: B_TRUE if vni, B_FALSE if not.
+ */
+boolean_t
+i_ipadm_is_vni(const char *ifname)
+{
+	ifspec_t	ifsp;
+
+	return (ifparse_ifspec(ifname, &ifsp) &&
+	    strcmp(ifsp.ifsp_devnm, "vni") == 0);
+}
+
+/*
+ * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
+ */
+boolean_t
+i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
+{
+	dladm_status_t		dlstatus;
+	datalink_class_t	class;
+	iptun_params_t		params;
+	datalink_id_t		linkid;
+
+	if (iph->iph_dlh == NULL) {
+		assert(getzoneid() != GLOBAL_ZONEID);
+		return (B_FALSE);
+	}
+	dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
+	    &class, NULL);
+	if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
+		params.iptun_param_linkid = linkid;
+		dlstatus = dladm_iptun_getparams(iph->iph_dlh, &params,
+		    DLADM_OPT_ACTIVE);
+		if (dlstatus == DLADM_STATUS_OK &&
+		    params.iptun_param_type == IPTUN_TYPE_6TO4) {
+			return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
+
+/*
+ * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
+ */
+boolean_t
+i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
+{
+	struct lifreq	lifr;
+
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
+		if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
+		    (caddr_t)&lifr) < 0) {
+			return (B_FALSE);
+		}
+	}
+	return (lifr.lifr_groupname[0] != '\0');
+}
+
+/*
+ * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
+ */
+boolean_t
+i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
+{
+	uint64_t flags;
+
+	if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
+	    i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
+		return (B_FALSE);
+
+	return ((flags & IFF_IPMP) != 0);
+}
+
+/*
+ * For a given interface name, ipadm_if_enabled() checks if v4
+ * or v6 or both IP interfaces exist in the active configuration.
+ */
+boolean_t
+ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
+{
+	struct lifreq	lifr;
+	int		s4 = iph->iph_sock;
+	int		s6 = iph->iph_sock6;
+
+	bzero(&lifr, sizeof (lifr));
+	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
+	switch (af) {
+	case AF_INET:
+		if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
+			return (B_TRUE);
+		break;
+	case AF_INET6:
+		if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
+			return (B_TRUE);
+		break;
+	case AF_UNSPEC:
+		if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
+		    ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
+			return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
+
+/*
+ * Apply the interface property by retrieving information from nvl.
+ */
+static ipadm_status_t
+i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
+{
+	nvpair_t	*nvp;
+	char		*name, *pname = NULL;
+	char		*protostr = NULL, *ifname = NULL, *pval = NULL;
+	uint_t		proto;
+	int		err = 0;
+
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
+			if ((err = nvpair_value_string(nvp, &ifname)) != 0)
+				break;
+		} else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
+			if ((err = nvpair_value_string(nvp, &protostr)) != 0)
+				break;
+		} else {
+			assert(!IPADM_PRIV_NVP(name));
+			pname = name;
+			if ((err = nvpair_value_string(nvp, &pval)) != 0)
+				break;
+		}
+	}
+	if (err != 0)
+		return (ipadm_errno2status(err));
+	proto = ipadm_str2proto(protostr);
+	return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
+	    IPADM_OPT_ACTIVE));
+}
+
+/*
+ * Instantiate the address object or set the address object property by
+ * retrieving the configuration from the nvlist `nvl'.
+ */
+ipadm_status_t
+i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
+{
+	nvpair_t	*nvp;
+	char		*name;
+	char		*aobjname = NULL, *pval = NULL, *ifname = NULL;
+	sa_family_t	af = AF_UNSPEC;
+	ipadm_addr_type_t atype = IPADM_ADDR_NONE;
+	int		err = 0;
+	ipadm_status_t	status = IPADM_SUCCESS;
+
+	for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(nvl, nvp)) {
+		name = nvpair_name(nvp);
+		if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
+			if ((err = nvpair_value_string(nvp, &ifname)) != 0)
+				break;
+		} else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
+			if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
+				break;
+		} else if (i_ipadm_name2atype(name, &af, &atype)) {
+			break;
+		} else {
+			assert(!IPADM_PRIV_NVP(name));
+			err = nvpair_value_string(nvp, &pval);
+			break;
+		}
+	}
+	if (err != 0)
+		return (ipadm_errno2status(err));
+
+	switch (atype) {
+	case IPADM_ADDR_STATIC:
+		status = i_ipadm_enable_static(iph, ifname, nvl, af);
+		break;
+	case IPADM_ADDR_DHCP:
+		status = i_ipadm_enable_dhcp(iph, ifname, nvl);
+		if (status == IPADM_DHCP_IPC_TIMEOUT)
+			status = IPADM_SUCCESS;
+		break;
+	case IPADM_ADDR_IPV6_ADDRCONF:
+		status = i_ipadm_enable_addrconf(iph, ifname, nvl);
+		break;
+	case IPADM_ADDR_NONE:
+		status = ipadm_set_addrprop(iph, name, pval, aobjname,
+		    IPADM_OPT_ACTIVE);
+		break;
+	}
+
+	return (status);
+}
+
+/*
+ * Instantiate the interface object by retrieving the configuration from
+ * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
+ * (interface properties and address objects on that interface) for the
+ * given `ifname'.
+ */
+ipadm_status_t
+i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
+{
+	nvlist_t	*nvl = NULL;
+	nvpair_t	*nvp;
+	char		*afstr;
+	ipadm_status_t	status;
+	ipadm_status_t	ret_status = IPADM_SUCCESS;
+	char		newifname[LIFNAMSIZ];
+	char		*aobjstr;
+
+	(void) strlcpy(newifname, ifname, sizeof (newifname));
+	/*
+	 * First plumb the given interface and then apply all the persistent
+	 * interface properties and then instantiate any persistent addresses
+	 * objects on that interface.
+	 */
+	for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
+	    nvp = nvlist_next_nvpair(ifnvl, nvp)) {
+		if (nvpair_value_nvlist(nvp, &nvl) != 0)
+			continue;
+
+		if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
+			status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
+			    IPADM_OPT_ACTIVE);
+			/*
+			 * If the interface is already plumbed, we should
+			 * ignore this error because there might be address
+			 * address objects on that interface that needs to
+			 * be enabled again.
+			 */
+			if (status == IPADM_IF_EXISTS)
+				status = IPADM_SUCCESS;
+		} 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'.
+			 */
+			if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
+			    nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
+				status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
+				    nvl, aobjstr);
+				if (status != IPADM_SUCCESS)
+					continue;
+			}
+			status = i_ipadm_init_addrobj(iph, nvl);
+			/*
+			 * If this address is in use on some other interface,
+			 * we want to record an error to be returned as
+			 * a soft error and continue processing the rest of
+			 * the addresses.
+			 */
+			if (status == IPADM_ADDR_NOTAVAIL) {
+				ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
+				status = IPADM_SUCCESS;
+			}
+		} else {
+			assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
+			status = i_ipadm_init_ifprop(iph, nvl);
+		}
+		if (status != IPADM_SUCCESS)
+			return (status);
+	}
+	return (ret_status);
+}
+
+/*
+ * Retrieves the persistent configuration for the given interface(s) in `ifs'
+ * by contacting the daemon and dumps the information in `allifs'.
+ */
+ipadm_status_t
+i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
+{
+	nvlist_t		*nvl = NULL;
+	size_t			nvlsize, bufsize;
+	ipmgmt_initif_arg_t	*iargp;
+	char			*buf = NULL, *nvlbuf = NULL;
+	ipmgmt_get_rval_t	*rvalp = NULL;
+	int			err;
+	ipadm_status_t		status = IPADM_SUCCESS;
+
+	if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
+		return (ipadm_errno2status(err));
+
+	err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
+	if (err != 0) {
+		status = ipadm_errno2status(err);
+		goto done;
+	}
+	bufsize = sizeof (*iargp) + nvlsize;
+	if ((buf = malloc(bufsize)) == NULL) {
+		status = ipadm_errno2status(errno);
+		goto done;
+	}
+
+	/* populate the door_call argument structure */
+	iargp = (void *)buf;
+	iargp->ia_cmd = IPMGMT_CMD_INITIF;
+	iargp->ia_flags = 0;
+	iargp->ia_family = AF_UNSPEC;
+	iargp->ia_nvlsize = nvlsize;
+	(void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
+
+	if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
+		status = ipadm_errno2status(errno);
+		goto done;
+	}
+	if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
+	    sizeof (*rvalp), B_TRUE)) != 0) {
+		status = ipadm_errno2status(err);
+		goto done;
+	}
+	nvlsize = rvalp->ir_nvlsize;
+	nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
+
+	/*
+	 * nvlbuf contains a list of nvlists, each of which represents
+	 * configuration information for the given interface(s)
+	 */
+	err = nvlist_unpack(nvlbuf, nvlsize, allifs, NV_ENCODE_NATIVE);
+	if (err != 0)
+		status = ipadm_errno2status(err);
+done:
+	nvlist_free(nvl);
+	free(buf);
+	free(nvlbuf);
+	free(rvalp);
+	return (status);
+}
+
+/*
+ * Returns B_FALSE if
+ * (1) `ifname' is NULL or has no string or has a string of invalid length
+ * (2) ifname is a logical interface and IPH_LEGACY is not set, or
+ */
+boolean_t
+i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
+{
+	ifspec_t ifsp;
+
+	if (ifname == NULL || ifname[0] == '\0' ||
+	    !ifparse_ifspec(ifname, &ifsp))
+		return (B_FALSE);
+	if (ifsp.ifsp_lunvalid)
+		return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
+	return (B_TRUE);
+}
+
+/*
+ * Wrapper for sending a non-transparent I_STR ioctl().
+ * Returns: Result from ioctl().
+ */
+int
+i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
+{
+	struct strioctl ioc;
+
+	(void) memset(&ioc, 0, sizeof (ioc));
+	ioc.ic_cmd = cmd;
+	ioc.ic_timout = 0;
+	ioc.ic_len = buflen;
+	ioc.ic_dp = buf;
+
+	return (ioctl(s, I_STR, (char *)&ioc));
+}
+
+/*
+ * Make a door call to the server and checks if the door call succeeded or not.
+ * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
+ * variable size and door will allocate buffer using mmap(). In such cases
+ * we re-allocate the required memory,n assign it to `rbufp', copy the data to
+ * `rbufp' and then call munmap() (see below).
+ *
+ * It also checks to see if the server side procedure ran successfully by
+ * checking for ir_err. Therefore, for some callers who just care about the
+ * return status can set `rbufp' to NULL and set `rsize' to 0.
+ */
+int
+ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
+    size_t rsize, boolean_t is_varsize)
+{
+	door_arg_t	darg;
+	int		err;
+	ipmgmt_retval_t	rval, *rvalp;
+
+	if (rbufp == NULL) {
+		rvalp = &rval;
+		rbufp = (void **)&rvalp;
+		rsize = sizeof (rval);
+	}
+
+	darg.data_ptr = arg;
+	darg.data_size = asize;
+	darg.desc_ptr = NULL;
+	darg.desc_num = 0;
+	darg.rbuf = *rbufp;
+	darg.rsize = rsize;
+
+	(void) pthread_mutex_lock(&iph->iph_lock);
+	/* The door descriptor is opened if it isn't already */
+	if (iph->iph_door_fd == -1) {
+		if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
+			err = errno;
+			(void) pthread_mutex_unlock(&iph->iph_lock);
+			return (err);
+		}
+	}
+	(void) pthread_mutex_unlock(&iph->iph_lock);
+
+	if (door_call(iph->iph_door_fd, &darg) == -1)
+		return (errno);
+	err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
+	if (darg.rbuf != *rbufp) {
+		/*
+		 * if the caller is expecting the result to fit in specified
+		 * buffer then return failure.
+		 */
+		if (!is_varsize)
+			err = EBADE;
+		/*
+		 * The size of the buffer `*rbufp' was not big enough
+		 * and the door itself allocated buffer, for us. We will
+		 * hit this, on several occasion as for some cases
+		 * we cannot predict the size of the return structure.
+		 * Reallocate the buffer `*rbufp' and memcpy() the contents
+		 * to new buffer.
+		 */
+		if (err == 0) {
+			void *newp;
+
+			/* allocated memory will be freed by the caller */
+			if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
+				err = ENOMEM;
+			} else {
+				*rbufp = newp;
+				(void) memcpy(*rbufp, darg.rbuf, darg.rsize);
+			}
+		}
+		/* munmap() the door buffer */
+		(void) munmap(darg.rbuf, darg.rsize);
+	} else {
+		if (darg.rsize != rsize)
+			err = EBADE;
+	}
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/libipadm.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,346 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _LIBIPADM_H
+#define	_LIBIPADM_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+#include <libnvpair.h>
+#include <netinet/tcp.h>
+#include <sys/stropts.h>
+
+#define	IPADM_AOBJ_USTRSIZ	32
+#define	IPADM_AOBJSIZ		(LIFNAMSIZ + IPADM_AOBJ_USTRSIZ)
+#define	MAXPROPVALLEN		512
+#define	LOOPBACK_IF		"lo0"
+
+/* special timeout values for dhcp operations */
+#define	IPADM_DHCP_WAIT_DEFAULT	(-1)
+#define	IPADM_DHCP_WAIT_FOREVER	(-2)
+
+/*
+ * Specifies that the string passed to ipadm_str2nvlist() is a string of comma
+ * separated names and that each name does not have values associated with it.
+ */
+#define	IPADM_NORVAL		0x00000001
+
+/* error codes */
+typedef enum {
+	IPADM_SUCCESS,		/* No error occurred */
+	IPADM_FAILURE,		/* Generic failure */
+	IPADM_EAUTH,		/* Insufficient user authorizations */
+	IPADM_EPERM,		/* Permission denied */
+	IPADM_NO_BUFS,		/* No Buffer space available */
+	IPADM_NO_MEMORY,	/* Insufficient memory */
+	IPADM_BAD_ADDR,		/* Invalid address */
+	IPADM_BAD_PROTOCOL,	/* Wrong protocol family for operation */
+	IPADM_DAD_FOUND,	/* Duplicate address detected */
+	IPADM_EXISTS,		/* Already exists */
+	IPADM_IF_EXISTS,	/* Interface already exists */
+	IPADM_ADDROBJ_EXISTS,	/* Address object already exists */
+	IPADM_ADDRCONF_EXISTS,	/* Addrconf already in progress */
+	IPADM_ENXIO,		/* Interface does not exist */
+	IPADM_GRP_NOTEMPTY,	/* IPMP Group non-empty on unplumb */
+	IPADM_INVALID_ARG,	/* Invalid argument */
+	IPADM_INVALID_NAME,	/* Invalid name */
+	IPADM_DLPI_FAILURE,	/* Could not open DLPI link */
+	IPADM_DLADM_FAILURE,	/* DLADM error encountered */
+	IPADM_PROP_UNKNOWN,	/* Unknown property */
+	IPADM_ERANGE,		/* Value is outside the allowed range */
+	IPADM_ESRCH,		/* Value does not exist */
+	IPADM_EOVERFLOW,	/* Number of values exceed the allowed limit */
+	IPADM_NOTFOUND,		/* Object not found */
+	IPADM_IF_INUSE,		/* Interface already in use */
+	IPADM_ADDR_INUSE,	/* Address alrelady in use */
+	IPADM_BAD_HOSTNAME,	/* hostname maps to multiple IP addresses */
+	IPADM_ADDR_NOTAVAIL,	/* Can't assign requested address */
+	IPADM_ALL_ADDRS_NOT_ENABLED, /* All addresses could not be enabled */
+	IPADM_NDPD_NOT_RUNNING,	/* in.ndpd not running */
+	IPADM_DHCP_START_ERROR,	/* Cannot start dhcpagent */
+	IPADM_DHCP_IPC_ERROR,	/* Cannot communicate with dhcpagent */
+	IPADM_DHCP_IPC_TIMEOUT,	/* Communication with dhcpagent timed out */
+	IPADM_TEMPORARY_OBJ,	/* Permanent operation on temporary object */
+	IPADM_IPC_ERROR,	/* Cannot communicate with ipmgmtd */
+	IPADM_OP_DISABLE_OBJ,	/* Operation on disable object */
+	IPADM_NOTSUP,		/* Operation not supported */
+	IPADM_EBADE		/* Invalid data exchange with ipmgmtd */
+} ipadm_status_t;
+
+/*
+ * option flags taken by the libipadm functions
+ *
+ *  - 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.
+ *
+ *  - IPADM_OPT_ACTIVE:
+ *	Requests to apply configuration without persisting it and
+ *	used by show-* subcommands to retrieve current values.
+ *
+ *  - IPADM_OPT_DEFAULT:
+ *	retrieves the default value for a given property
+ *
+ *  - IPADM_OPT_PERM
+ *	retrieves the permission for a given property
+ *
+ *  - IPADM_OPT_POSSIBLE
+ *	retrieves the range of values for a given property
+ *
+ *  - IPADM_OPT_APPEND
+ *	for multi-valued properties, appends a new value.
+ *
+ *  - IPADM_OPT_REMOVE
+ *	for multi-valued properties, removes the specified value
+ *
+ *  - IPADM_OPT_IPMP
+ *	Used in ipadm_create_if() to plumb ipmp interfaces.
+ *
+ *  - IPADM_OPT_GENPPA
+ *	Used in ipadm_create_if() to generate a ppa for the given interface.
+ *
+ *  - IPADM_OPT_ZEROADDR
+ *	return :: or INADDR_ANY
+ *
+ *  - IPADM_OPT_RELEASE
+ *	Used to release the lease on a dhcp address object
+ *
+ *  - IPADM_OPT_INFORM
+ *	Used to perform DHCP_INFORM on a specified static address object
+ *
+ *  - IPADM_OPT_UP
+ *	Used to bring up a static address on creation
+ */
+#define	IPADM_OPT_PERSIST	0x00000001
+#define	IPADM_OPT_ACTIVE	0x00000002
+#define	IPADM_OPT_DEFAULT	0x00000004
+#define	IPADM_OPT_PERM		0x00000008
+#define	IPADM_OPT_POSSIBLE	0x00000010
+#define	IPADM_OPT_APPEND	0x00000020
+#define	IPADM_OPT_REMOVE	0x00000040
+#define	IPADM_OPT_IPMP		0x00000080
+#define	IPADM_OPT_GENPPA	0x00000100
+#define	IPADM_OPT_ZEROADDR	0x00000200
+#define	IPADM_OPT_RELEASE	0x00000400
+#define	IPADM_OPT_INFORM	0x00000800
+#define	IPADM_OPT_UP		0x00001000
+
+/* IPADM property class */
+#define	IPADMPROP_CLASS_MODULE	0x00000001	/* on 'protocol' only */
+#define	IPADMPROP_CLASS_IF	0x00000002	/* on 'IP interface' only */
+#define	IPADMPROP_CLASS_ADDR	0x00000004	/* on 'IP address' only */
+/* protocol property that can be applied on interface too */
+#define	IPADMPROP_CLASS_MODIF	(IPADMPROP_CLASS_MODULE | IPADMPROP_CLASS_IF)
+
+/* opaque ipadm handle to libipadm functions */
+struct ipadm_handle;
+typedef struct ipadm_handle	*ipadm_handle_t;
+
+/* ipadm_handle flags */
+#define	IPH_VRRP		0x00000001	/* Caller is VRRP */
+#define	IPH_LEGACY		0x00000002	/* Caller is legacy app */
+
+/* opaque address object structure */
+typedef struct ipadm_addrobj_s	*ipadm_addrobj_t;
+
+/* ipadm_if_info_t states */
+typedef enum {
+	IFIS_OK,		/* Interface is usable */
+	IFIS_DOWN,		/* Interface has no UP addresses */
+	IFIS_FAILED,		/* Interface has failed. */
+	IFIS_OFFLINE,		/* Interface has been offlined */
+	IFIS_DISABLED		/* Interface has been disabled. */
+} ipadm_if_state_t;
+
+typedef struct ipadm_if_info_s {
+	struct ipadm_if_info_s	*ifi_next;
+	char			ifi_name[LIFNAMSIZ];	/* interface name */
+	ipadm_if_state_t	ifi_state;		/* see above */
+	uint_t			ifi_cflags;		/* current flags */
+	uint_t			ifi_pflags;		/* persistent flags */
+} ipadm_if_info_t;
+
+/* ipadm_if_info_t flags */
+#define	IFIF_BROADCAST		0x00000001
+#define	IFIF_MULTICAST		0x00000002
+#define	IFIF_POINTOPOINT	0x00000004
+#define	IFIF_VIRTUAL		0x00000008
+#define	IFIF_IPMP		0x00000010
+#define	IFIF_STANDBY		0x00000020
+#define	IFIF_INACTIVE		0x00000040
+#define	IFIF_VRRP		0x00000080
+#define	IFIF_NOACCEPT		0x00000100
+#define	IFIF_IPV4		0x00000200
+#define	IFIF_IPV6		0x00000400
+
+/* ipadm_addr_info_t state */
+typedef enum {
+	IFA_DISABLED,		/* Address not in active configuration. */
+	IFA_DUPLICATE,		/* DAD failed. */
+	IFA_DOWN,		/* Address is not IFF_UP */
+	IFA_TENTATIVE,		/* DAD verification initiated */
+	IFA_OK,			/* Address is usable */
+	IFA_INACCESSIBLE	/* Interface has failed */
+} ipadm_addr_state_t;
+
+/* possible address types */
+typedef enum  {
+	IPADM_ADDR_NONE,
+	IPADM_ADDR_STATIC,
+	IPADM_ADDR_IPV6_ADDRCONF,
+	IPADM_ADDR_DHCP
+} ipadm_addr_type_t;
+
+typedef struct ipadm_addr_info_s {
+	struct ifaddrs		ia_ifa;		/* list of addresses */
+	char			ia_sname[NI_MAXHOST];	/* local hostname */
+	char			ia_dname[NI_MAXHOST];	/* remote hostname */
+	char			ia_aobjname[IPADM_AOBJSIZ];
+	uint_t			ia_cflags;	/* active flags */
+	uint_t			ia_pflags;	/* persistent flags */
+	ipadm_addr_type_t	ia_atype;	/* see above */
+	ipadm_addr_state_t	ia_state;	/* see above */
+} ipadm_addr_info_t;
+#define	IA_NEXT(ia)		((ipadm_addr_info_t *)(ia->ia_ifa.ifa_next))
+
+/* ipadm_addr_info_t flags */
+#define	IA_UP			0x00000001
+#define	IA_UNNUMBERED		0x00000002
+#define	IA_PRIVATE		0x00000004
+#define	IA_TEMPORARY		0x00000008
+#define	IA_DEPRECATED		0x00000010
+
+/* open/close libipadm handle */
+extern ipadm_status_t	ipadm_open(ipadm_handle_t *, uint32_t);
+extern void		ipadm_close(ipadm_handle_t);
+
+/* Check authorization for network configuration */
+extern boolean_t	ipadm_check_auth(void);
+/*
+ * Interface mangement functions
+ */
+extern ipadm_status_t	ipadm_create_if(ipadm_handle_t, char *, sa_family_t,
+			    uint32_t);
+extern ipadm_status_t	ipadm_disable_if(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_enable_if(ipadm_handle_t, const char *, uint32_t);
+extern ipadm_status_t	ipadm_if_info(ipadm_handle_t, const char *,
+			    ipadm_if_info_t **, uint32_t, int64_t);
+extern void		ipadm_free_if_info(ipadm_if_info_t *);
+extern ipadm_status_t	ipadm_delete_if(ipadm_handle_t, const char *,
+			    sa_family_t, uint32_t);
+
+/*
+ * Address management functions
+ */
+extern ipadm_status_t	ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
+			    uint32_t);
+extern ipadm_status_t	ipadm_disable_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_enable_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_addr_info(ipadm_handle_t, const char *,
+			    ipadm_addr_info_t **, uint32_t, int64_t);
+extern void		ipadm_free_addr_info(ipadm_addr_info_t *);
+extern ipadm_status_t	ipadm_up_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_down_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_refresh_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+extern ipadm_status_t	ipadm_delete_addr(ipadm_handle_t, const char *,
+			    uint32_t);
+
+/* Functions related to creating/deleting/modifying opaque address object */
+extern ipadm_status_t	ipadm_create_addrobj(ipadm_addr_type_t, const char *,
+			    ipadm_addrobj_t *);
+extern void		ipadm_destroy_addrobj(ipadm_addrobj_t);
+
+/* Functions to set fields in addrobj for static addresses */
+extern ipadm_status_t	ipadm_set_addr(ipadm_addrobj_t, const char *,
+			    sa_family_t);
+extern ipadm_status_t	ipadm_set_dst_addr(ipadm_addrobj_t, const char *,
+			    sa_family_t);
+
+/* Functions to set fields in addrobj for IPv6 addrconf */
+extern ipadm_status_t	ipadm_set_interface_id(ipadm_addrobj_t, const char *);
+extern ipadm_status_t	ipadm_set_stateless(ipadm_addrobj_t, boolean_t);
+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);
+
+/*
+ * Property management functions
+ */
+/* call back function for the property walker */
+typedef boolean_t	ipadm_prop_wfunc_t(void *, const char *, uint_t);
+extern ipadm_status_t	ipadm_walk_proptbl(uint_t, uint_t, ipadm_prop_wfunc_t *,
+			    void *);
+extern ipadm_status_t	ipadm_walk_prop(const char *, uint_t, uint_t,
+			    ipadm_prop_wfunc_t *, void *);
+
+/* Interface property management - set, reset and get */
+extern ipadm_status_t	ipadm_set_ifprop(ipadm_handle_t, const char *,
+			    const char *, const char *, uint_t, uint_t);
+extern ipadm_status_t	ipadm_get_ifprop(ipadm_handle_t, const char *,
+			    const char *, char *, uint_t *, uint_t, uint_t);
+
+/* Address property management - set, reset and get */
+extern ipadm_status_t	ipadm_set_addrprop(ipadm_handle_t, const char *,
+			    const char *, const char *, uint_t);
+extern ipadm_status_t	ipadm_get_addrprop(ipadm_handle_t, const char *, char *,
+			    uint_t *, const char *, uint_t);
+
+/* Protoocl property management - set, reset and get */
+extern ipadm_status_t	ipadm_set_prop(ipadm_handle_t, const char *,
+			    const char *, uint_t, uint_t);
+extern ipadm_status_t	ipadm_get_prop(ipadm_handle_t, const char *, char *,
+			    uint_t *, uint_t, uint_t);
+extern ipadm_status_t	ipadm_init_prop(void);
+
+/*
+ * miscellaneous helper functions.
+ */
+extern const char 	*ipadm_status2str(ipadm_status_t);
+extern int		ipadm_str2nvlist(const char *, nvlist_t **, uint_t);
+extern size_t		ipadm_nvlist2str(nvlist_t *, char *, size_t);
+extern char		*ipadm_proto2str(uint_t);
+extern uint_t		ipadm_str2proto(const char *);
+extern ipadm_status_t	ipadm_open_arp_on_udp(const char *, int *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBIPADM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/libipadm_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,227 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIBIPADM_IMPL_H
+#define	_LIBIPADM_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/socket.h>
+#include <net/if.h>
+#include <libipadm.h>
+#include <libdladm.h>
+#include <ipadm_ipmgmt.h>
+#include <inet/tunables.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <libinetutil.h>
+#include <libsocket_priv.h>
+
+#define	IPADM_STRSIZE		256
+#define	IPADM_ONSTR		"on"
+#define	IPADM_OFFSTR		"off"
+#define	ARP_MOD_NAME		"arp"
+#define	IPADM_LOGICAL_SEP	':'
+#define	IPV6_MIN_MTU		1280	/* rfc2460 */
+
+/* mask for flags accepted by libipadm functions */
+#define	IPADM_COMMON_OPT_MASK	(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST)
+
+/* Opaque library handle */
+struct ipadm_handle {
+	int		iph_sock;	/* socket to interface */
+	int		iph_sock6;	/* socket to interface */
+	int		iph_door_fd;	/* door descriptor to ipmgmtd */
+	dladm_handle_t	iph_dlh;	/* handle to libdladm library */
+	uint32_t	iph_flags;	/* internal flags */
+	pthread_mutex_t	iph_lock;	/* lock to set door_fd */
+};
+
+/*
+ * Indicates that the operation being invoked is in 'init' context. This is
+ * a library private flag.
+ */
+#define	IPH_INIT	0x10000000
+
+struct ipadm_addrobj_s {
+	char 			ipadm_ifname[LIFNAMSIZ];
+	int32_t			ipadm_lifnum;
+	char			ipadm_aobjname[IPADM_AOBJSIZ];
+	ipadm_addr_type_t	ipadm_atype;
+	uint32_t		ipadm_flags;
+	sa_family_t		ipadm_af;
+	union {
+		struct {
+			char			ipadm_ahname[MAXNAMELEN];
+			struct sockaddr_storage	ipadm_addr;
+			uint32_t		ipadm_prefixlen;
+			char			ipadm_dhname[MAXNAMELEN];
+			struct sockaddr_storage ipadm_dstaddr;
+		} ipadm_static_addr_s;
+		struct {
+			struct sockaddr_in6	ipadm_intfid;
+			uint32_t		ipadm_intfidlen;
+			boolean_t		ipadm_stateless;
+			boolean_t		ipadm_stateful;
+		} ipadm_ipv6_intfid_s;
+		struct {
+			boolean_t		ipadm_primary;
+			int32_t			ipadm_wait;
+		} ipadm_dhcp_s;
+	} ipadm_addr_u;
+};
+
+#define	ipadm_static_addr	ipadm_addr_u.ipadm_static_addr_s.ipadm_addr
+#define	ipadm_static_aname	ipadm_addr_u.ipadm_static_addr_s.ipadm_ahname
+#define	ipadm_static_prefixlen	ipadm_addr_u.ipadm_static_addr_s.ipadm_prefixlen
+#define	ipadm_static_dst_addr	ipadm_addr_u.ipadm_static_addr_s.ipadm_dstaddr
+#define	ipadm_static_dname	ipadm_addr_u.ipadm_static_addr_s.ipadm_dhname
+#define	ipadm_intfid		ipadm_addr_u.ipadm_ipv6_intfid_s.ipadm_intfid
+#define	ipadm_intfidlen		ipadm_addr_u.ipadm_ipv6_intfid_s.ipadm_intfidlen
+#define	ipadm_stateless		ipadm_addr_u.ipadm_ipv6_intfid_s.ipadm_stateless
+#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
+
+/*
+ * Data structures and callback functions related to property management
+ */
+struct ipadm_prop_desc;
+typedef struct ipadm_prop_desc ipadm_prop_desc_t;
+
+/* property set() callback */
+typedef ipadm_status_t	ipadm_pd_setf_t(ipadm_handle_t, const void *,
+    ipadm_prop_desc_t *, const void *, uint_t, uint_t);
+
+/* property get() callback */
+typedef ipadm_status_t	ipadm_pd_getf_t(ipadm_handle_t, const void *,
+    ipadm_prop_desc_t *, char *, uint_t *, uint_t, uint_t);
+
+struct ipadm_prop_desc {
+	char		*ipd_name;	/* property name */
+	uint_t		ipd_class; 	/* prop. class - global/perif/both */
+	uint_t		ipd_proto;	/* protocol to which property belongs */
+	ipadm_pd_setf_t	*ipd_set;	/* set callback function */
+	ipadm_pd_getf_t	*ipd_get_range;	/* get range callback function */
+	ipadm_pd_getf_t	*ipd_get;	/* get value callback function */
+};
+
+extern ipadm_prop_desc_t	ipadm_addrprop_table[];
+extern ipadm_pd_getf_t		i_ipadm_get_onoff;
+
+/* libipadm.c */
+extern ipadm_status_t	i_ipadm_get_flags(ipadm_handle_t, const char *,
+			    sa_family_t, uint64_t *);
+extern ipadm_status_t	i_ipadm_set_flags(ipadm_handle_t, const char *,
+			    sa_family_t, uint64_t, uint64_t);
+extern ipadm_status_t	i_ipadm_init_ifs(ipadm_handle_t, const char *,
+			    nvlist_t **);
+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);
+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 *);
+extern boolean_t	i_ipadm_is_vni(const char *);
+extern boolean_t	i_ipadm_is_ipmp(ipadm_handle_t, const char *);
+extern boolean_t	i_ipadm_is_under_ipmp(ipadm_handle_t, const char *);
+extern boolean_t	i_ipadm_is_6to4(ipadm_handle_t, char *);
+extern boolean_t	i_ipadm_validate_ifname(ipadm_handle_t, const char *);
+extern ipadm_status_t	ipadm_errno2status(int);
+extern int		ipadm_door_call(ipadm_handle_t, void *, size_t, void **,
+			    size_t, boolean_t);
+extern boolean_t 	ipadm_if_enabled(ipadm_handle_t, const char *,
+			    sa_family_t);
+
+/* ipadm_ndpd.c */
+extern	ipadm_status_t	i_ipadm_create_ipv6addrs(ipadm_handle_t,
+			    ipadm_addrobj_t, uint32_t);
+extern ipadm_status_t	i_ipadm_delete_ipv6addrs(ipadm_handle_t,
+			    ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_disable_autoconf(const char *);
+extern ipadm_status_t	i_ipadm_enable_autoconf(const char *);
+
+/* ipadm_persist.c */
+extern ipadm_status_t	i_ipadm_add_ipaddr2nvl(nvlist_t *, ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_add_ip6addr2nvl(nvlist_t *, ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_add_intfid2nvl(nvlist_t *, ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_add_dhcp2nvl(nvlist_t *, boolean_t, int32_t);
+
+/* ipadm_prop.c */
+extern ipadm_status_t	i_ipadm_persist_propval(ipadm_handle_t,
+			    ipadm_prop_desc_t *, const char *, const void *,
+			    uint_t);
+extern ipadm_status_t	i_ipadm_get_persist_propval(ipadm_handle_t,
+			    ipadm_prop_desc_t *, char *, uint_t *,
+			    const void *);
+
+/* 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 *,
+			    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 *,
+			    nvlist_t *, sa_family_t);
+extern ipadm_status_t	i_ipadm_enable_dhcp(ipadm_handle_t, const char *,
+			    nvlist_t *);
+extern ipadm_status_t	i_ipadm_enable_addrconf(ipadm_handle_t, const char *,
+			    nvlist_t *);
+extern void		i_ipadm_addrobj2lifname(ipadm_addrobj_t, char *, int);
+extern ipadm_status_t	i_ipadm_nvl2in6_addr(nvlist_t *, char *,
+			    in6_addr_t *);
+extern ipadm_status_t	i_ipadm_get_lif2addrobj(ipadm_handle_t,
+			    ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_lookupadd_addrobj(ipadm_handle_t,
+			    ipadm_addrobj_t);
+extern ipadm_status_t	i_ipadm_delete_addrobj(ipadm_handle_t,
+			    const ipadm_addrobj_t, uint32_t);
+extern boolean_t	i_ipadm_name2atype(const char *, sa_family_t *,
+			    ipadm_addr_type_t *);
+
+/* ipadm_if.c */
+extern ipadm_status_t	i_ipadm_create_if(ipadm_handle_t, char *,  sa_family_t,
+			    uint32_t);
+extern ipadm_status_t	i_ipadm_delete_if(ipadm_handle_t, const char *,
+			    sa_family_t, uint32_t);
+extern ipadm_status_t	i_ipadm_plumb_if(ipadm_handle_t, char *, sa_family_t,
+			    uint32_t);
+extern ipadm_status_t	i_ipadm_unplumb_if(ipadm_handle_t, const char *,
+			    sa_family_t);
+extern ipadm_status_t	i_ipadm_if_pexists(ipadm_handle_t, const char *,
+			    sa_family_t, boolean_t *);
+extern ipadm_status_t	i_ipadm_delete_ifobj(ipadm_handle_t, const char *,
+			    sa_family_t, boolean_t);
+extern int		i_ipadm_get_lnum(const char *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBIPADM_IMPL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/llib-lipadm	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,35 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libipadm.h>
+/*
+ * functions private to libipadm and ipmgmtd/in.ndpd are prototyped
+ * in the files below
+ */
+#include <ipadm_ipmgmt.h>
+#include <ipadm_ndpd.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/common/mapfile-vers	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,93 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+    global:
+	ipadm_add_aobjname;
+	ipadm_addr_info;
+	ipadm_check_auth;
+	ipadm_close;
+	ipadm_create_addr;
+	ipadm_create_addrobj;
+	ipadm_create_if;
+	ipadm_delete_addr;
+	ipadm_delete_aobjname;
+	ipadm_delete_if;
+	ipadm_destroy_addrobj;
+	ipadm_disable_addr;
+	ipadm_disable_if;
+	ipadm_down_addr;
+	ipadm_enable_addr;
+	ipadm_enable_if;
+	ipadm_free_addr_info;
+	ipadm_free_if_info;
+	ipadm_get_addrprop;
+	ipadm_get_ifprop;
+	ipadm_get_prop;
+	ipadm_if_enabled;
+	ipadm_if_info;
+	ipadm_init_prop;
+	ipadm_ndpd_read;
+	ipadm_ndpd_write;
+	ipadm_nvlist2str;
+	ipadm_open;
+	ipadm_open_arp_on_udp;
+	ipadm_proto2str;
+	ipadm_refresh_addr;
+	ipadm_rw_db;
+	ipadm_set_addr;
+	ipadm_set_addrprop;
+	ipadm_set_dst_addr;
+	ipadm_set_ifprop;
+	ipadm_set_interface_id;
+	ipadm_set_primary;
+	ipadm_set_prop;
+	ipadm_set_stateful;
+	ipadm_set_stateless;
+	ipadm_set_wait_time;
+	ipadm_status2str;
+	ipadm_str2nvlist;
+	ipadm_str2proto;
+	ipadm_up_addr;
+	ipadm_walk_prop;
+	ipadm_walk_proptbl;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/i386/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/libipadm.xcl	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,89 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+msgid  ""
+msgid  "%c%c"
+msgid  "%d"
+msgid  "%d,%s"
+msgid  "%s"
+msgid  "%s%d"
+msgid  "%s,%s"
+msgid  "%s/%s"
+msgid  "%s/%s.new"
+msgid  "%s0"
+msgid  "%s:%d"
+msgid  "%s="
+msgid  "%s=%s"
+msgid  "%u"
+msgid  ","
+msgid  ",%s"
+msgid  "/"
+msgid  "/%d,%s,%s"
+msgid  "0"
+msgid  "1"
+msgid  "1-126,128"
+msgid  "1-30,32"
+msgid  "active"
+msgid  "all-zones"
+msgid  "arp"
+msgid  "broadcast"
+msgid  "deprecated"
+msgid  "ecn"
+msgid  "exchange_routes"
+msgid  "extra_priv_ports"
+msgid  "forwarding"
+msgid  "hoplimit"
+msgid  "icmp"
+msgid  "ip"
+msgid  "ipmpstub0"
+msgid  "ipv4"
+msgid  "ipv6"
+msgid  "largest_anon_port"
+msgid  "metric"
+msgid  "mtu"
+msgid  "never"
+msgid  "no"
+msgid  "nud"
+msgid  "passive"
+msgid  "prefixlen"
+msgid  "private"
+msgid  "r"
+msgid  "r+"
+msgid  "recv_maxbuf"
+msgid  "sack"
+msgid  "sctp"
+msgid  "send_maxbuf"
+msgid  "smallest_anon_port"
+msgid  "smallest_nonpriv_port"
+msgid  "tcp"
+msgid  "transmit"
+msgid  "ttl"
+msgid  "udp"
+msgid  "up"
+msgid  "usesrc"
+msgid  "vni"
+msgid  "w"
+msgid  "yes"
+msgid  "zone"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libipadm/sparc/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# 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]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- a/usr/src/lib/libsecdb/auth_attr.txt	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsecdb/auth_attr.txt	Fri Mar 26 17:53:11 2010 -0400
@@ -97,6 +97,7 @@
 solaris.network.autoconf.write:::Create Network Auto-Magic Config::help=NetworkAutoconfWrite.html
 solaris.network.ilb.config:::Network ILB Configuration::help=NetworkILBconf.html
 solaris.network.ilb.enable:::Network ILB Enable Configuration::help=NetworkILBenable.html
+solaris.network.interface.config:::Network Interface Configuration::help=NetworkInterfaceConfig.html
 solaris.network.link.security:::Link Security::help=LinkSecurity.html
 solaris.network.wifi.config:::Wifi Config::help=WifiConfig.html
 solaris.network.wifi.wep:::Wifi Wep::help=WifiWep.html
--- a/usr/src/lib/libsecdb/exec_attr.txt	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Fri Mar 26 17:53:11 2010 -0400
@@ -175,6 +175,8 @@
 Network Management:solaris:cmd:::/sbin/flowadm:euid=dladm;egid=sys;\
 	privs=sys_dl_config,net_rawaccess,proc_audit
 Network Management:solaris:cmd:::/sbin/flowstat:euid=dladm;egid=sys;
+Network Management:solaris:cmd:::/sbin/ipadm:euid=netadm;egid=netadm;\
+	privs=sys_ip_config,net_rawaccess
 Network Management:suser:cmd:::/usr/bin/netstat:uid=0
 Network Management:suser:cmd:::/usr/bin/rup:euid=0
 Network Management:suser:cmd:::/usr/bin/ruptime:euid=0
--- a/usr/src/lib/libsecdb/help/auths/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsecdb/help/auths/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -129,6 +129,7 @@
 	NetworkILBenable.html \
 	NetworkHeader.html \
 	NetworkVRRP.html \
+	NetworkInterfaceConfig.html \
 	WifiConfig.html \
 	WifiWep.html \
 	LinkSecurity.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,42 @@
+<html>
+
+<!--
+    Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+    Use is subject to license terms.
+
+    CDDL HEADER START
+
+    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]
+
+    CDDL HEADER END
+-->
+
+<head>
+<!--
+meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"
+-->
+</head>
+<body>
+When Network Interface Configuration is in the Authorizations
+Included column, it grants permission to create/delete/show network IP
+interfaces on data-links. It also grants permission to set/reset/get tunables on
+protocol modules.
+<p>
+Note that querying configuration information on Network IP interfaces or the
+protocol module properties doesn't require the Network Interface Configuration
+authorization.
+</body>
+</html>
--- a/usr/src/lib/libsecdb/prof_attr.txt	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsecdb/prof_attr.txt	Fri Mar 26 17:53:11 2010 -0400
@@ -65,7 +65,7 @@
 Network Autoconf User:::Network Auto-Magic User:auths=solaris.network.autoconf.read,solaris.network.autoconf.select,solaris.network.autoconf.wlan;help=RtNetAutoconfUser.html
 Network ILB:::Manage ILB configuration via ilbadm:auths=solaris.network.ilb.config,solaris.network.ilb.enable;help=RtNetILB.html
 Network VRRP:::Manage VRRP instances:auths=solaris.network.vrrp,solaris.smf.manage.vrrp;help=RtNetVRRP.html
-Network Management:::Manage the host and network configuration:auths=solaris.smf.manage.name-service-cache,solaris.smf.manage.bind,solaris.smf.value.routing,solaris.smf.manage.routing,solaris.smf.value.nwam,solaris.smf.manage.nwam,solaris.smf.manage.tnd,solaris.smf.manage.tnctl,solaris.smf.manage.wpa,solaris.smf.value.mdns,solaris.smf.manage.mdns,solaris.smf.manage.ilb;profiles=Network Wifi Management,Inetd Management,Network VRRP,Network Observability;help=RtNetMngmnt.html
+Network Management:::Manage the host and network configuration:auths=solaris.smf.manage.name-service-cache,solaris.smf.manage.bind,solaris.smf.value.routing,solaris.smf.manage.routing,solaris.smf.value.nwam,solaris.smf.manage.nwam,solaris.smf.manage.tnd,solaris.smf.manage.tnctl,solaris.smf.manage.wpa,solaris.smf.value.mdns,solaris.smf.manage.mdns,solaris.smf.manage.ilb,solaris.network.interface.config;profiles=Network Wifi Management,Inetd Management,Network VRRP,Network Observability;help=RtNetMngmnt.html
 Network Observability:::Allow access to observability devices:privs=net_observability;help=RtNetObservability.html
 Network Security:::Manage network and host security:auths=solaris.smf.manage.ssh,solaris.smf.value.tnd,solaris.network.*;profiles=Network Wifi Security,Network Link Security,Network IPsec Management;help=RtNetSecure.html
 Network Wifi Management:::Manage wifi network configuration:auths=solaris.network.wifi.config;help=RtNetWifiMngmnt.html
--- a/usr/src/lib/libsocket/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsocket/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -18,15 +18,14 @@
 #
 # CDDL HEADER END
 #
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 include ../Makefile.lib
 
+HDRS = libsocket_priv.h
+HDRDIR = common
 SUBDIRS = $(MACH)
 $(BUILD64)SUBDIRS += $(MACH64)
 
@@ -45,6 +44,10 @@
 
 all clean clobber install lint: $(SUBDIRS)
 
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
 _msg: $(MSGDOMAINPOFILE)
 
 $(POFILE): pofile_MSGFILES
@@ -54,4 +57,5 @@
 
 FRC:
 
+include $(SRC)/lib/Makefile.targ
 include $(SRC)/Makefile.msg.targ
--- a/usr/src/lib/libsocket/Makefile.com	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsocket/Makefile.com	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -32,7 +32,8 @@
 		getprotoent.o getprotoent_r.o getservbyname_r.o getservent.o \
 		getservent_r.o inet_lnaof.o inet_mkaddr.o inet_network.o \
 		inet6_opt.o inet6_rthdr.o interface_id.o link_addr.o \
-		netmasks.o rcmd.o rexec.o ruserpass.o sourcefilter.o
+		netmasks.o rcmd.o rexec.o ruserpass.o sourcefilter.o \
+		getifaddrs.o
 SOCKOBJS =	_soutil.o sockatmark.o socket.o socketpair.o weaks.o
 OBJECTS	=	$(INETOBJS) $(SOCKOBJS)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsocket/common/libsocket_priv.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#ifndef _LIBSOCKET_PRIV_H
+#define	_LIBSOCKET_PRIV_H
+
+#include <net/if.h>
+#include <ifaddrs.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+extern int	getallifaddrs(sa_family_t, struct ifaddrs **, int64_t);
+extern int	getallifs(int, sa_family_t, struct lifreq **, int *, int64_t);
+extern int	getnetmaskbyaddr(const struct in_addr, struct in_addr *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBSOCKET_PRIV_H */
--- a/usr/src/lib/libsocket/common/llib-lsocket	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsocket/common/llib-lsocket	Fri Mar 26 17:53:11 2010 -0400
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,10 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 /* LINTLIBRARY */
 /* PROTOLIB1 */
@@ -38,6 +36,8 @@
 #include <sys/ethernet.h>
 #include <netdb.h>
 #include <net/if_dl.h>
+#include <ifaddrs.h>
+#include <libsocket_priv.h>
 
 /*
  * usr/src/lib/libsocket/inet routines not prototyped in the above
@@ -56,7 +56,6 @@
 
 /* netmasks.c */
 int getnetmaskbynet(const struct in_addr net, struct in_addr *mask);
-int getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask);
 
 /* ruserpass.c */
 void _ruserpass(const char *host, char **aname, char **apass);
--- a/usr/src/lib/libsocket/common/mapfile-vers	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/lib/libsocket/common/mapfile-vers	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -37,6 +37,12 @@
 # MAPFILE HEADER END
 #
 
+SUNW_1.7 {
+    global:
+	freeifaddrs;
+	getifaddrs;
+} SUNW_1.6;
+
 SUNW_1.6 {
     global:
 	getipv4sourcefilter;
@@ -157,6 +163,8 @@
 	_nss_initf_netmasks;
 	_nss_initf_proto;
 	_nss_initf_services;
+	getallifaddrs;
+	getallifs;
 	str2ether;
 	str2addr;
 	str2netent;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsocket/inet/getifaddrs.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,269 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <netdb.h>
+#include <nss_dbdefs.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/sockio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+#include <libsocket_priv.h>
+
+/*
+ * Create a linked list of `struct ifaddrs' structures, one for each
+ * address that is UP. If successful, store the list in *ifap and
+ * return 0.  On errors, return -1 and set `errno'.
+ *
+ * The storage returned in *ifap is allocated dynamically and can
+ * only be properly freed by passing it to `freeifaddrs'.
+ */
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+	int		err;
+	char		*cp;
+	struct ifaddrs	*curr;
+
+	if (ifap == NULL) {
+		errno = EINVAL;
+		return (-1);
+	}
+	*ifap = NULL;
+	err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
+	if (err == 0) {
+		for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
+			if ((cp = strchr(curr->ifa_name, ':')) != NULL)
+				*cp = '\0';
+		}
+	}
+	return (err);
+}
+
+void
+freeifaddrs(struct ifaddrs *ifa)
+{
+	struct ifaddrs *curr;
+
+	while (ifa != NULL) {
+		curr = ifa;
+		ifa = ifa->ifa_next;
+		free(curr->ifa_name);
+		free(curr->ifa_addr);
+		free(curr->ifa_netmask);
+		free(curr->ifa_dstaddr);
+		free(curr);
+	}
+}
+
+/*
+ * Returns all addresses configured on the system. If flags contain
+ * LIFC_ENABLED, only the addresses that are UP are returned.
+ * Address list that is returned by this function must be freed
+ * using freeifaddrs().
+ */
+int
+getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
+{
+	struct lifreq *buf = NULL;
+	struct lifreq *lifrp;
+	struct lifreq lifrl;
+	int ret;
+	int s, n, numifs;
+	struct ifaddrs *curr, *prev;
+	sa_family_t lifr_af;
+	int sock4;
+	int sock6;
+	int err;
+
+	if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+		return (-1);
+	if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+		err = errno;
+		close(sock4);
+		errno = err;
+		return (-1);
+	}
+
+retry:
+	/* Get all interfaces from SIOCGLIFCONF */
+	ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
+	if (ret != 0)
+		goto fail;
+
+	/*
+	 * Loop through the interfaces obtained from SIOCGLIFCOMF
+	 * and retrieve the addresses, netmask and flags.
+	 */
+	prev = NULL;
+	lifrp = buf;
+	*ifap = NULL;
+	for (n = 0; n < numifs; n++, lifrp++) {
+
+		/* Prepare for the ioctl call */
+		(void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
+		    sizeof (lifrl.lifr_name));
+		lifr_af = lifrp->lifr_addr.ss_family;
+		if (af != AF_UNSPEC && lifr_af != af)
+			continue;
+
+		s = (lifr_af == AF_INET ? sock4 : sock6);
+
+		if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
+			goto fail;
+		if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
+			continue;
+
+		/*
+		 * Allocate the current list node. Each node contains data
+		 * for one ifaddrs structure.
+		 */
+		curr = calloc(1, sizeof (struct ifaddrs));
+		if (curr == NULL)
+			goto fail;
+
+		if (prev != NULL) {
+			prev->ifa_next = curr;
+		} else {
+			/* First node in the linked list */
+			*ifap = curr;
+		}
+		prev = curr;
+
+		curr->ifa_flags = lifrl.lifr_flags;
+		if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
+			goto fail;
+
+		curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
+		if (curr->ifa_addr == NULL)
+			goto fail;
+		*curr->ifa_addr = lifrp->lifr_addr;
+
+		/* Get the netmask */
+		if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
+			goto fail;
+		curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
+		if (curr->ifa_netmask == NULL)
+			goto fail;
+		*curr->ifa_netmask = lifrl.lifr_addr;
+
+		/* Get the destination for a pt-pt interface */
+		if (curr->ifa_flags & IFF_POINTOPOINT) {
+			if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
+				goto fail;
+			curr->ifa_dstaddr = malloc(
+			    sizeof (struct sockaddr_storage));
+			if (curr->ifa_dstaddr == NULL)
+				goto fail;
+			*curr->ifa_dstaddr = lifrl.lifr_addr;
+		} else if (curr->ifa_flags & IFF_BROADCAST) {
+			if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
+				goto fail;
+			curr->ifa_broadaddr = malloc(
+			    sizeof (struct sockaddr_storage));
+			if (curr->ifa_broadaddr == NULL)
+				goto fail;
+			*curr->ifa_broadaddr = lifrl.lifr_addr;
+		}
+
+	}
+	free(buf);
+	close(sock4);
+	close(sock6);
+	return (0);
+fail:
+	err = errno;
+	free(buf);
+	freeifaddrs(*ifap);
+	*ifap = NULL;
+	if (err == ENXIO)
+		goto retry;
+	close(sock4);
+	close(sock6);
+	errno = err;
+	return (-1);
+}
+
+/*
+ * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
+ */
+int
+getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
+    int64_t lifc_flags)
+{
+	struct lifnum lifn;
+	struct lifconf lifc;
+	size_t bufsize;
+	char *tmp;
+	caddr_t *buf = (caddr_t *)lifr;
+
+	lifn.lifn_family = af;
+	lifn.lifn_flags = lifc_flags;
+
+	*buf = NULL;
+retry:
+	if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
+		goto fail;
+
+	/*
+	 * When calculating the buffer size needed, add a small number
+	 * of interfaces to those we counted.  We do this to capture
+	 * the interface status of potential interfaces which may have
+	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
+	 */
+	bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
+
+	if ((tmp = realloc(*buf, bufsize)) == NULL)
+		goto fail;
+
+	*buf = tmp;
+	lifc.lifc_family = af;
+	lifc.lifc_flags = lifc_flags;
+	lifc.lifc_len = bufsize;
+	lifc.lifc_buf = *buf;
+	if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
+		goto fail;
+
+	*numifs = lifc.lifc_len / sizeof (struct lifreq);
+	if (*numifs >= (lifn.lifn_count + 4)) {
+		/*
+		 * If every entry was filled, there are probably
+		 * more interfaces than (lifn.lifn_count + 4).
+		 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
+		 * get all the interfaces.
+		 */
+		goto retry;
+	}
+	return (0);
+fail:
+	free(*buf);
+	*buf = NULL;
+	return (-1);
+}
--- a/usr/src/pkg/manifests/SUNWcs.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/SUNWcs.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -486,6 +486,7 @@
 file path=etc/vfstab group=sys preserve=true
 file path=lib/crypto/kcfd mode=0555
 file path=lib/inet/in.mpathd mode=0555
+file path=lib/inet/ipmgmtd mode=0555
 file path=lib/inet/netcfgd mode=0555
 file path=lib/inet/nwamd mode=0555
 file path=lib/svc/bin/lsvcrun group=sys mode=0555
@@ -512,6 +513,7 @@
 file path=lib/svc/method/manifest-import mode=0555
 file path=lib/svc/method/mpxio-upgrade mode=0555
 file path=lib/svc/method/net-init mode=0555
+file path=lib/svc/method/net-ipmgmt mode=0555
 file path=lib/svc/method/net-ipqos mode=0555
 file path=lib/svc/method/net-iptun mode=0555
 file path=lib/svc/method/net-loc mode=0555
@@ -968,6 +970,7 @@
 file path=usr/lib/help/auths/locale/C/NetworkHeader.html
 file path=usr/lib/help/auths/locale/C/NetworkILBconf.html
 file path=usr/lib/help/auths/locale/C/NetworkILBenable.html
+file path=usr/lib/help/auths/locale/C/NetworkInterfaceConfig.html
 file path=usr/lib/help/auths/locale/C/NetworkVRRP.html
 file path=usr/lib/help/auths/locale/C/PriAdmin.html
 file path=usr/lib/help/auths/locale/C/ProfmgrHeader.html
@@ -1930,6 +1933,7 @@
 file path=lib/svc/manifest/network/ipsec/policy.xml group=sys mode=0444
 file path=lib/svc/manifest/network/ldap/client.xml group=sys mode=0444
 file path=lib/svc/manifest/network/network-initial.xml group=sys mode=0444
+file path=lib/svc/manifest/network/network-ipmgmt.xml group=sys mode=0444
 file path=lib/svc/manifest/network/network-ipqos.xml group=sys mode=0444
 file path=lib/svc/manifest/network/network-iptun.xml group=sys mode=0444
 file path=lib/svc/manifest/network/network-location.xml group=sys mode=0444
@@ -2689,6 +2693,7 @@
 link path=usr/sbin/inetd target=../lib/inet/inetd
 link path=usr/sbin/init target=../../sbin/init
 $(i386_ONLY)link path=usr/sbin/installgrub target=../../sbin/installgrub
+link path=usr/sbin/ipadm target=../../sbin/ipadm
 link path=usr/sbin/ipmpstat target=../../sbin/ipmpstat
 link path=usr/sbin/labelit target=./clri
 link path=usr/sbin/lockfs target=../lib/fs/ufs/lockfs
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -137,6 +137,7 @@
 file path=usr/lib/help/auths/locale/NetworkHeader.html
 file path=usr/lib/help/auths/locale/NetworkILBconf.html
 file path=usr/lib/help/auths/locale/NetworkILBenable.html
+file path=usr/lib/help/auths/locale/NetworkInterfaceConfig.html
 file path=usr/lib/help/auths/locale/NetworkVRRP.html
 file path=usr/lib/help/auths/locale/PriAdmin.html
 file path=usr/lib/help/auths/locale/PrintAdmin.html
--- a/usr/src/pkg/manifests/system-header.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/system-header.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -383,6 +383,7 @@
 file path=usr/include/iconv.h
 file path=usr/include/idmap.h
 file path=usr/include/ieeefp.h
+file path=usr/include/ifaddrs.h
 file path=usr/include/inet/arp.h
 file path=usr/include/inet/common.h
 file path=usr/include/inet/ip.h
@@ -412,6 +413,7 @@
 file path=usr/include/inet/tcp_sack.h
 file path=usr/include/inet/tcp_stack.h
 file path=usr/include/inet/tcp_stats.h
+file path=usr/include/inet/tunables.h
 file path=usr/include/inet/wifi_ioctl.h
 file path=usr/include/inttypes.h
 file path=usr/include/ipmp.h
--- a/usr/src/pkg/manifests/system-kernel.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/system-kernel.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -214,8 +214,6 @@
 driver name=sad perms="admin 0666 root sys" perms="user 0666 root sys"
 driver name=scsi_vhci class=scsi-self-identifying perms="* 0666 root sys" \
     policy="devctl write_priv_set=sys_devices"
-driver name=sctp perms="* 0666 root sys"
-driver name=sctp6 perms="* 0666 root sys"
 $(sparc_ONLY)driver name=sd perms="* 0640 root sys" \
     alias=ide-cdrom \
     alias=scsiclass,00 \
@@ -365,8 +363,6 @@
 file path=kernel/drv/$(ARCH64)/rts group=sys
 file path=kernel/drv/$(ARCH64)/sad group=sys
 file path=kernel/drv/$(ARCH64)/scsi_vhci group=sys
-file path=kernel/drv/$(ARCH64)/sctp group=sys
-file path=kernel/drv/$(ARCH64)/sctp6 group=sys
 file path=kernel/drv/$(ARCH64)/sd group=sys
 file path=kernel/drv/$(ARCH64)/sgen group=sys
 file path=kernel/drv/$(ARCH64)/simnet group=sys
@@ -507,10 +503,6 @@
 file path=kernel/drv/scsi_vhci.conf group=sys \
     original_name=SUNWckr:kernel/drv/scsi_vhci.conf preserve=true \
     reboot-needed=false
-$(i386_ONLY)file path=kernel/drv/sctp group=sys
-file path=kernel/drv/sctp.conf group=sys reboot-needed=false
-$(i386_ONLY)file path=kernel/drv/sctp6 group=sys
-file path=kernel/drv/sctp6.conf group=sys reboot-needed=false
 $(sparc_ONLY)file path=kernel/drv/sd.conf group=sys \
     original_name=SUNWckr:kernel/drv/sd.conf preserve=true reboot-needed=false
 $(i386_ONLY)file path=kernel/drv/sgen group=sys
--- a/usr/src/pkg/manifests/system-library.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/system-library.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -181,6 +181,7 @@
 file path=lib/libinetcfg.so.1
 file path=lib/libinetutil.so.1
 file path=lib/libintl.so.1
+file path=lib/libipadm.so.1
 file path=lib/libipmp.so.1
 file path=lib/libkcfd.so.1
 file path=lib/libkmf.so.1
--- a/usr/src/pkg/manifests/system-network.mf	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/pkg/manifests/system-network.mf	Fri Mar 26 17:53:11 2010 -0400
@@ -40,6 +40,7 @@
 dir path=etc/inet/ike/publickeys group=sys
 dir path=etc/inet/secret group=sys mode=0700
 dir path=etc/inet/secret/ike.privatekeys group=sys mode=0700
+dir path=etc/ipadm group=netadm owner=netadm
 dir path=etc/nwam group=netadm owner=netadm
 dir path=etc/nwam/loc group=netadm owner=netadm
 dir path=etc/nwam/loc/NoNet group=netadm owner=netadm
@@ -70,6 +71,7 @@
 file path=etc/inet/secret/ipseckeys.sample group=sys mode=0600
 file path=etc/inet/sock2path group=sys \
     original_name=SUNWcnetr:etc/inet/sock2path preserve=true
+file path=etc/ipadm/ipadm.conf group=netadm owner=netadm preserve=true
 file path=etc/nwam/loc/NoNet/ipf.conf.dfl group=netadm owner=netadm \
     preserve=true
 file path=etc/nwam/loc/NoNet/ipf6.conf.dfl group=netadm owner=netadm \
@@ -81,6 +83,7 @@
 file path=sbin/flowadm mode=0555
 file path=sbin/flowstat mode=0555
 group groupname=netadm gid=65
+file path=sbin/ipadm mode=0555
 legacy pkg=SUNWcnetr arch=$(ARCH) category=system \
     desc="core software for network infrastructure configuration" \
     hotline="Please contact your local service provider" \
--- a/usr/src/tools/scripts/bfu.sh	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/tools/scripts/bfu.sh	Fri Mar 26 17:53:11 2010 -0400
@@ -93,6 +93,7 @@
 	etc/inet/*
 	etc/init.d/*
 	etc/inittab
+	etc/ipadm/ipadm.conf
 	etc/ipf/ipf.conf
 	etc/iu.ap
 	etc/krb5/kadm5.acl
@@ -2451,6 +2452,12 @@
 	fi
 
 	#
+	# Import the ip-interface-management service.
+	#
+	smf_import_service network/network-ipmgmt.xml \
+	    svc:/network/ip-interface-management:default
+
+	#
 	# Import the ldap/client service. This is to get the service
 	# (with correct dependencies) in the repository before reboot.
 	#
@@ -3145,6 +3152,7 @@
 	/usr/sbin/chroot
 	/usr/sbin/fstyp
 	/usr/sbin/halt
+	/usr/sbin/ifconfig
 	/usr/sbin/lockfs
 	/usr/sbin/lofiadm
 	/usr/sbin/logadm
@@ -3152,6 +3160,7 @@
 	/usr/sbin/mkfs
 	/usr/sbin/mknod
 	/usr/sbin/mount
+	/usr/sbin/ndd
 	/usr/sbin/newfs
 	/usr/sbin/pkgrm
 	/usr/sbin/prtconf
@@ -7963,6 +7972,16 @@
 	rm -f $root/kernel/drv/mscsi.conf
 	rm -f $root/platform/i86pc/kernel/drv/amd64/mscsi
 
+	# Remove sctp, sctp6
+	rm -f $root/kernel/drv/sctp
+	rm -f $root/kernel/drv/sctp.conf
+	rm -f $root/kernel/drv/sctp6
+	rm -f $root/kernel/drv/sctp6.conf
+	rm -f $root/kernel/drv/amd64/sctp
+	rm -f $root/kernel/drv/amd64/sctp6
+	rm -f $root/kernel/drv/sparcv9/sctp
+	rm -f $root/kernel/drv/sparcv9/sctp6
+
 	# Remove obsolete pfil modules, binaries, and configuration files
 	rm -f $root/kernel/drv/pfil
 	rm -f $root/kernel/drv/pfil.conf
--- a/usr/src/uts/common/Makefile.files	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/Makefile.files	Fri Mar 26 17:53:11 2010 -0400
@@ -529,24 +529,25 @@
 IP_RTS_OBJS =	rts.o rts_opt_data.o
 IP_TCP_OBJS =	tcp.o tcp_fusion.o tcp_kssl.o tcp_opt_data.o tcp_sack.o \
 		tcp_stats.o tcp_misc.o tcp_timers.o tcp_time_wait.o tcp_tpi.o \
-		tcp_output.o tcp_input.o tcp_socket.o tcp_bind.o tcp_cluster.o
-IP_UDP_OBJS =	udp.o udp_opt_data.o
+		tcp_output.o tcp_input.o tcp_socket.o tcp_bind.o tcp_cluster.o \
+		tcp_tunables.o
+IP_UDP_OBJS =	udp.o udp_opt_data.o udp_tunables.o
 IP_SCTP_OBJS =	sctp.o sctp_opt_data.o sctp_output.o \
 		sctp_init.o sctp_input.o sctp_cookie.o \
 		sctp_conn.o sctp_error.o sctp_snmp.o \
-		sctp_param.o sctp_shutdown.o sctp_common.o \
+		sctp_tunables.o sctp_shutdown.o sctp_common.o \
 		sctp_timer.o sctp_heartbeat.o sctp_hash.o \
-		sctp_ioc.o sctp_bind.o sctp_notify.o sctp_asconf.o \
+		sctp_bind.o sctp_notify.o sctp_asconf.o \
 		sctp_addr.o tn_ipopt.o tnet.o ip_netinfo.o
 IP_ILB_OBJS =	ilb.o ilb_nat.o ilb_conn.o ilb_alg_hash.o ilb_alg_rr.o
 
 IP_OBJS +=	igmp.o ipmp.o ip.o ip6.o ip6_asp.o ip6_if.o ip6_ire.o \
 		ip6_rts.o ip_if.o ip_ire.o ip_listutils.o ip_mroute.o \
 		ip_multi.o ip2mac.o ip_ndp.o ip_rts.o ip_srcid.o \
-		ipddi.o ipdrop.o mi.o nd.o optcom.o snmpcom.o ipsec_loader.o \
-		spd.o ipclassifier.o inet_common.o ip_squeue.o squeue.o \
-		ip_sadb.o ip_ftable.o proto_set.o radix.o ip_dummy.o \
-		ip_helper_stream.o \
+		ipddi.o ipdrop.o mi.o nd.o tunables.o optcom.o snmpcom.o \
+		ipsec_loader.o spd.o ipclassifier.o inet_common.o ip_squeue.o \
+		squeue.o ip_sadb.o ip_ftable.o proto_set.o radix.o ip_dummy.o \
+		ip_helper_stream.o ip_tunables.o \
 		ip_output.o ip_input.o ip6_input.o ip6_output.o ip_arp.o \
 		conn_opt.o ip_attr.o ip_dce.o \
 		$(IP_ICMP_OBJS) \
@@ -585,10 +586,6 @@
 
 TCP6_OBJS +=	tcp6ddi.o
 
-SCTP_OBJS +=	sctpddi.o
-
-SCTP6_OBJS +=	sctp6ddi.o
-
 NCA_OBJS +=	ncaddi.o
 
 SDP_SOCK_MOD_OBJS += sockmod_sdp.o socksdp.o socksdpsubr.o
--- a/usr/src/uts/common/inet/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/Makefile	Fri Mar 26 17:53:11 2010 -0400
@@ -32,7 +32,7 @@
 	ipsecah.h ipsecesp.h ipsec_info.h iptun.h ip6_asp.h ip_if.h ip_ire.h \
 	ip_multi.h ip_netinfo.h ip_ndp.h ip_rts.h ipsec_impl.h keysock.h \
 	led.h mi.h mib2.h nd.h optcom.h sadb.h sctp_itf.h snmpcom.h tcp.h \
-	tcp_sack.h tcp_stack.h udp_impl.h rawip_impl.h ipp_common.h \
+	tcp_sack.h tcp_stack.h tunables.h udp_impl.h rawip_impl.h ipp_common.h \
 	ip_ftable.h ip_impl.h ip_stack.h ip_arp.h tcp_impl.h wifi_ioctl.h \
 	ip2mac.h ip2mac_impl.h tcp_stats.h
 
--- a/usr/src/uts/common/inet/ip.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip.h	Fri Mar 26 17:53:11 2010 -0400
@@ -174,11 +174,11 @@
 #define	IPOPTP_ERROR	0x00000001
 #endif	/* _KERNEL */
 
-/* Controls forwarding of IP packets, set via ndd */
+/* Controls forwarding of IP packets, set via ipadm(1M)/ndd(1M) */
 #define	IP_FORWARD_NEVER	0
 #define	IP_FORWARD_ALWAYS	1
 
-#define	WE_ARE_FORWARDING(ipst)	((ipst)->ips_ip_g_forward == IP_FORWARD_ALWAYS)
+#define	WE_ARE_FORWARDING(ipst)	((ipst)->ips_ip_forwarding == IP_FORWARD_ALWAYS)
 
 #define	IPH_HDR_LENGTH(ipha)						\
 	((int)(((ipha_t *)ipha)->ipha_version_and_hdr_length & 0xF) << 2)
@@ -945,7 +945,6 @@
 	in6_addr_t ipif_v6brd_addr;	/* Broadcast addr for this interface. */
 	in6_addr_t ipif_v6pp_dst_addr;	/* Point-to-point dest address. */
 	uint64_t ipif_flags;		/* Interface flags. */
-	uint_t	ipif_metric;		/* BSD if metric, for compatibility. */
 	uint_t	ipif_ire_type;		/* IRE_LOCAL or IRE_LOOPBACK */
 
 	/*
@@ -1018,7 +1017,6 @@
  * ipif_v6brd_addr
  * ipif_v6pp_dst_addr
  * ipif_flags		ill_lock		ill_lock
- * ipif_metric
  * ipif_ire_type	ipsq + down ill		up ill
  *
  * ipif_ib_pkt_count	Approx
@@ -1608,10 +1606,10 @@
 	uint_t	ill_max_frag;		/* Max IDU from DLPI. */
 	uint_t	ill_current_frag;	/* Current IDU from DLPI. */
 	uint_t	ill_mtu;		/* User-specified MTU; SIOCSLIFMTU */
+	uint_t	ill_metric;		/* BSD if metric, for compatibility. */
 	char	*ill_name;		/* Our name. */
 	uint_t	ill_ipif_dup_count;	/* Number of duplicate addresses. */
 	uint_t	ill_name_length;	/* Name length, incl. terminator. */
-	char	*ill_ndd_name;		/* Name + ":ip?_forwarding" for NDD. */
 	uint_t	ill_net_type;		/* IRE_IF_RESOLVER/IRE_IF_NORESOLVER. */
 	/*
 	 * Physical Point of Attachment num.  If DLPI style 1 provider
@@ -1691,7 +1689,11 @@
 		ill_fragtimer_executing : 1,
 		ill_fragtimer_needrestart : 1,
 		ill_manual_token : 1,	/* system won't override ill_token */
-		ill_manual_linklocal : 1, /* system won't auto-conf linklocal */
+		/*
+		 * ill_manual_linklocal : system will not change the
+		 * linklocal whenever ill_token changes.
+		 */
+		ill_manual_linklocal : 1,
 
 		ill_manual_dst_linklocal : 1, /* same for pt-pt dst linklocal */
 
@@ -2025,14 +2027,6 @@
 	IDCS_FAILED
 };
 
-/* Named Dispatch Parameter Management Structure */
-typedef struct ipparam_s {
-	uint_t	ip_param_min;
-	uint_t	ip_param_max;
-	uint_t	ip_param_value;
-	char	*ip_param_name;
-} ipparam_t;
-
 /* Extended NDP Management Structure */
 typedef struct ipndp_s {
 	ndgetf_t	ip_ndp_getf;
@@ -2932,88 +2926,94 @@
  * /etc/rc2.d/S69inet script.
  */
 
-#define	ips_ip_respond_to_address_mask_broadcast ips_param_arr[0].ip_param_value
-#define	ips_ip_g_resp_to_echo_bcast	ips_param_arr[1].ip_param_value
-#define	ips_ip_g_resp_to_echo_mcast	ips_param_arr[2].ip_param_value
-#define	ips_ip_g_resp_to_timestamp	ips_param_arr[3].ip_param_value
-#define	ips_ip_g_resp_to_timestamp_bcast ips_param_arr[4].ip_param_value
-#define	ips_ip_g_send_redirects		ips_param_arr[5].ip_param_value
-#define	ips_ip_g_forward_directed_bcast	ips_param_arr[6].ip_param_value
-#define	ips_ip_mrtdebug			ips_param_arr[7].ip_param_value
-#define	ips_ip_ire_reclaim_fraction	ips_param_arr[8].ip_param_value
-#define	ips_ip_nce_reclaim_fraction	ips_param_arr[9].ip_param_value
-#define	ips_ip_dce_reclaim_fraction	ips_param_arr[10].ip_param_value
-#define	ips_ip_def_ttl			ips_param_arr[11].ip_param_value
-#define	ips_ip_forward_src_routed	ips_param_arr[12].ip_param_value
-#define	ips_ip_wroff_extra		ips_param_arr[13].ip_param_value
-#define	ips_ip_pathmtu_interval		ips_param_arr[14].ip_param_value
-#define	ips_ip_icmp_return		ips_param_arr[15].ip_param_value
-#define	ips_ip_path_mtu_discovery	ips_param_arr[16].ip_param_value
-#define	ips_ip_pmtu_min			ips_param_arr[17].ip_param_value
-#define	ips_ip_ignore_redirect		ips_param_arr[18].ip_param_value
-#define	ips_ip_arp_icmp_error		ips_param_arr[19].ip_param_value
-#define	ips_ip_broadcast_ttl		ips_param_arr[20].ip_param_value
-#define	ips_ip_icmp_err_interval	ips_param_arr[21].ip_param_value
-#define	ips_ip_icmp_err_burst		ips_param_arr[22].ip_param_value
-#define	ips_ip_reass_queue_bytes	ips_param_arr[23].ip_param_value
-#define	ips_ip_strict_dst_multihoming	ips_param_arr[24].ip_param_value
-#define	ips_ip_addrs_per_if		ips_param_arr[25].ip_param_value
-#define	ips_ipsec_override_persocket_policy ips_param_arr[26].ip_param_value
-#define	ips_icmp_accept_clear_messages	ips_param_arr[27].ip_param_value
-#define	ips_igmp_accept_clear_messages	ips_param_arr[28].ip_param_value
+#define	ips_ip_respond_to_address_mask_broadcast \
+					ips_propinfo_tbl[0].prop_cur_bval
+#define	ips_ip_g_resp_to_echo_bcast	ips_propinfo_tbl[1].prop_cur_bval
+#define	ips_ip_g_resp_to_echo_mcast	ips_propinfo_tbl[2].prop_cur_bval
+#define	ips_ip_g_resp_to_timestamp	ips_propinfo_tbl[3].prop_cur_bval
+#define	ips_ip_g_resp_to_timestamp_bcast ips_propinfo_tbl[4].prop_cur_bval
+#define	ips_ip_g_send_redirects		ips_propinfo_tbl[5].prop_cur_bval
+#define	ips_ip_g_forward_directed_bcast	ips_propinfo_tbl[6].prop_cur_bval
+#define	ips_ip_mrtdebug			ips_propinfo_tbl[7].prop_cur_uval
+#define	ips_ip_ire_reclaim_fraction	ips_propinfo_tbl[8].prop_cur_uval
+#define	ips_ip_nce_reclaim_fraction	ips_propinfo_tbl[9].prop_cur_uval
+#define	ips_ip_dce_reclaim_fraction	ips_propinfo_tbl[10].prop_cur_uval
+#define	ips_ip_def_ttl			ips_propinfo_tbl[11].prop_cur_uval
+#define	ips_ip_forward_src_routed	ips_propinfo_tbl[12].prop_cur_bval
+#define	ips_ip_wroff_extra		ips_propinfo_tbl[13].prop_cur_uval
+#define	ips_ip_pathmtu_interval		ips_propinfo_tbl[14].prop_cur_uval
+#define	ips_ip_icmp_return		ips_propinfo_tbl[15].prop_cur_uval
+#define	ips_ip_path_mtu_discovery	ips_propinfo_tbl[16].prop_cur_bval
+#define	ips_ip_pmtu_min			ips_propinfo_tbl[17].prop_cur_uval
+#define	ips_ip_ignore_redirect		ips_propinfo_tbl[18].prop_cur_bval
+#define	ips_ip_arp_icmp_error		ips_propinfo_tbl[19].prop_cur_bval
+#define	ips_ip_broadcast_ttl		ips_propinfo_tbl[20].prop_cur_uval
+#define	ips_ip_icmp_err_interval	ips_propinfo_tbl[21].prop_cur_uval
+#define	ips_ip_icmp_err_burst		ips_propinfo_tbl[22].prop_cur_uval
+#define	ips_ip_reass_queue_bytes	ips_propinfo_tbl[23].prop_cur_uval
+#define	ips_ip_strict_dst_multihoming	ips_propinfo_tbl[24].prop_cur_uval
+#define	ips_ip_addrs_per_if		ips_propinfo_tbl[25].prop_cur_uval
+#define	ips_ipsec_override_persocket_policy ips_propinfo_tbl[26].prop_cur_bval
+#define	ips_icmp_accept_clear_messages	ips_propinfo_tbl[27].prop_cur_bval
+#define	ips_igmp_accept_clear_messages	ips_propinfo_tbl[28].prop_cur_bval
 
 /* IPv6 configuration knobs */
-#define	ips_delay_first_probe_time	ips_param_arr[29].ip_param_value
-#define	ips_max_unicast_solicit		ips_param_arr[30].ip_param_value
-#define	ips_ipv6_def_hops		ips_param_arr[31].ip_param_value
-#define	ips_ipv6_icmp_return		ips_param_arr[32].ip_param_value
-#define	ips_ipv6_forward_src_routed	ips_param_arr[33].ip_param_value
-#define	ips_ipv6_resp_echo_mcast	ips_param_arr[34].ip_param_value
-#define	ips_ipv6_send_redirects		ips_param_arr[35].ip_param_value
-#define	ips_ipv6_ignore_redirect	ips_param_arr[36].ip_param_value
-#define	ips_ipv6_strict_dst_multihoming	ips_param_arr[37].ip_param_value
-#define	ips_src_check			ips_param_arr[38].ip_param_value
-#define	ips_ipsec_policy_log_interval	ips_param_arr[39].ip_param_value
-#define	ips_pim_accept_clear_messages	ips_param_arr[40].ip_param_value
-#define	ips_ip_ndp_unsolicit_interval	ips_param_arr[41].ip_param_value
-#define	ips_ip_ndp_unsolicit_count	ips_param_arr[42].ip_param_value
-#define	ips_ipv6_ignore_home_address_opt ips_param_arr[43].ip_param_value
+#define	ips_delay_first_probe_time	ips_propinfo_tbl[29].prop_cur_uval
+#define	ips_max_unicast_solicit		ips_propinfo_tbl[30].prop_cur_uval
+#define	ips_ipv6_def_hops		ips_propinfo_tbl[31].prop_cur_uval
+#define	ips_ipv6_icmp_return		ips_propinfo_tbl[32].prop_cur_uval
+#define	ips_ipv6_forward_src_routed	ips_propinfo_tbl[33].prop_cur_bval
+#define	ips_ipv6_resp_echo_mcast	ips_propinfo_tbl[34].prop_cur_bval
+#define	ips_ipv6_send_redirects		ips_propinfo_tbl[35].prop_cur_bval
+#define	ips_ipv6_ignore_redirect	ips_propinfo_tbl[36].prop_cur_bval
+#define	ips_ipv6_strict_dst_multihoming	ips_propinfo_tbl[37].prop_cur_uval
+#define	ips_src_check			ips_propinfo_tbl[38].prop_cur_uval
+#define	ips_ipsec_policy_log_interval	ips_propinfo_tbl[39].prop_cur_uval
+#define	ips_pim_accept_clear_messages	ips_propinfo_tbl[40].prop_cur_bval
+#define	ips_ip_ndp_unsolicit_interval	ips_propinfo_tbl[41].prop_cur_uval
+#define	ips_ip_ndp_unsolicit_count	ips_propinfo_tbl[42].prop_cur_uval
+#define	ips_ipv6_ignore_home_address_opt ips_propinfo_tbl[43].prop_cur_bval
 
 /* Misc IP configuration knobs */
-#define	ips_ip_policy_mask		ips_param_arr[44].ip_param_value
-#define	ips_ip_ecmp_behavior		ips_param_arr[45].ip_param_value
-#define	ips_ip_multirt_ttl  		ips_param_arr[46].ip_param_value
-#define	ips_ip_ire_badcnt_lifetime	ips_param_arr[47].ip_param_value
-#define	ips_ip_max_temp_idle		ips_param_arr[48].ip_param_value
-#define	ips_ip_max_temp_defend		ips_param_arr[49].ip_param_value
-#define	ips_ip_max_defend		ips_param_arr[50].ip_param_value
-#define	ips_ip_defend_interval		ips_param_arr[51].ip_param_value
-#define	ips_ip_dup_recovery		ips_param_arr[52].ip_param_value
-#define	ips_ip_restrict_interzone_loopback ips_param_arr[53].ip_param_value
-#define	ips_ip_lso_outbound		ips_param_arr[54].ip_param_value
-#define	ips_igmp_max_version		ips_param_arr[55].ip_param_value
-#define	ips_mld_max_version		ips_param_arr[56].ip_param_value
-#define	ips_ipv6_drop_inbound_icmpv6	ips_param_arr[57].ip_param_value
-#define	ips_arp_probe_delay		ips_param_arr[58].ip_param_value
-#define	ips_arp_fastprobe_delay		ips_param_arr[59].ip_param_value
-#define	ips_arp_probe_interval		ips_param_arr[60].ip_param_value
-#define	ips_arp_fastprobe_interval	ips_param_arr[61].ip_param_value
-#define	ips_arp_probe_count		ips_param_arr[62].ip_param_value
-#define	ips_arp_fastprobe_count		ips_param_arr[63].ip_param_value
-#define	ips_ipv4_dad_announce_interval	ips_param_arr[64].ip_param_value
-#define	ips_ipv6_dad_announce_interval	ips_param_arr[65].ip_param_value
-#define	ips_arp_defend_interval		ips_param_arr[66].ip_param_value
-#define	ips_arp_defend_rate		ips_param_arr[67].ip_param_value
-#define	ips_ndp_defend_interval		ips_param_arr[68].ip_param_value
-#define	ips_ndp_defend_rate		ips_param_arr[69].ip_param_value
-#define	ips_arp_defend_period		ips_param_arr[70].ip_param_value
-#define	ips_ndp_defend_period		ips_param_arr[71].ip_param_value
-#define	ips_ipv4_icmp_return_pmtu	ips_param_arr[72].ip_param_value
-#define	ips_ipv6_icmp_return_pmtu	ips_param_arr[73].ip_param_value
-#define	ips_ip_arp_publish_count	ips_param_arr[74].ip_param_value
-#define	ips_ip_arp_publish_interval	ips_param_arr[75].ip_param_value
-#define	ips_ip_strict_src_multihoming	ips_param_arr[76].ip_param_value
-#define	ips_ipv6_strict_src_multihoming	ips_param_arr[77].ip_param_value
+#define	ips_ip_policy_mask		ips_propinfo_tbl[44].prop_cur_uval
+#define	ips_ip_ecmp_behavior		ips_propinfo_tbl[45].prop_cur_uval
+#define	ips_ip_multirt_ttl  		ips_propinfo_tbl[46].prop_cur_uval
+#define	ips_ip_ire_badcnt_lifetime	ips_propinfo_tbl[47].prop_cur_uval
+#define	ips_ip_max_temp_idle		ips_propinfo_tbl[48].prop_cur_uval
+#define	ips_ip_max_temp_defend		ips_propinfo_tbl[49].prop_cur_uval
+#define	ips_ip_max_defend		ips_propinfo_tbl[50].prop_cur_uval
+#define	ips_ip_defend_interval		ips_propinfo_tbl[51].prop_cur_uval
+#define	ips_ip_dup_recovery		ips_propinfo_tbl[52].prop_cur_uval
+#define	ips_ip_restrict_interzone_loopback ips_propinfo_tbl[53].prop_cur_bval
+#define	ips_ip_lso_outbound		ips_propinfo_tbl[54].prop_cur_bval
+#define	ips_igmp_max_version		ips_propinfo_tbl[55].prop_cur_uval
+#define	ips_mld_max_version		ips_propinfo_tbl[56].prop_cur_uval
+#define	ips_ip_forwarding		ips_propinfo_tbl[57].prop_cur_bval
+#define	ips_ipv6_forwarding		ips_propinfo_tbl[58].prop_cur_bval
+#define	ips_ip_reassembly_timeout	ips_propinfo_tbl[59].prop_cur_uval
+#define	ips_ipv6_reassembly_timeout	ips_propinfo_tbl[60].prop_cur_uval
+#define	ips_ip_cgtp_filter		ips_propinfo_tbl[61].prop_cur_bval
+#define	ips_arp_probe_delay		ips_propinfo_tbl[62].prop_cur_uval
+#define	ips_arp_fastprobe_delay		ips_propinfo_tbl[63].prop_cur_uval
+#define	ips_arp_probe_interval		ips_propinfo_tbl[64].prop_cur_uval
+#define	ips_arp_fastprobe_interval	ips_propinfo_tbl[65].prop_cur_uval
+#define	ips_arp_probe_count		ips_propinfo_tbl[66].prop_cur_uval
+#define	ips_arp_fastprobe_count		ips_propinfo_tbl[67].prop_cur_uval
+#define	ips_ipv4_dad_announce_interval	ips_propinfo_tbl[68].prop_cur_uval
+#define	ips_ipv6_dad_announce_interval	ips_propinfo_tbl[69].prop_cur_uval
+#define	ips_arp_defend_interval		ips_propinfo_tbl[70].prop_cur_uval
+#define	ips_arp_defend_rate		ips_propinfo_tbl[71].prop_cur_uval
+#define	ips_ndp_defend_interval		ips_propinfo_tbl[72].prop_cur_uval
+#define	ips_ndp_defend_rate		ips_propinfo_tbl[73].prop_cur_uval
+#define	ips_arp_defend_period		ips_propinfo_tbl[74].prop_cur_uval
+#define	ips_ndp_defend_period		ips_propinfo_tbl[75].prop_cur_uval
+#define	ips_ipv4_icmp_return_pmtu	ips_propinfo_tbl[76].prop_cur_bval
+#define	ips_ipv6_icmp_return_pmtu	ips_propinfo_tbl[77].prop_cur_bval
+#define	ips_ip_arp_publish_count	ips_propinfo_tbl[78].prop_cur_uval
+#define	ips_ip_arp_publish_interval	ips_propinfo_tbl[79].prop_cur_uval
+#define	ips_ip_strict_src_multihoming	ips_propinfo_tbl[80].prop_cur_uval
+#define	ips_ipv6_strict_src_multihoming	ips_propinfo_tbl[81].prop_cur_uval
+#define	ips_ipv6_drop_inbound_icmpv6	ips_propinfo_tbl[82].prop_cur_bval
 
 extern int	dohwcksum;	/* use h/w cksum if supported by the h/w */
 #ifdef ZC_TEST
--- a/usr/src/uts/common/inet/ip/icmp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/icmp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -128,10 +128,6 @@
 		    uchar_t *ptr);
 static int	icmp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin,
 		    sin6_t *sin6, cred_t *cr, pid_t pid, ip_xmit_attr_t *ixa);
-static int	icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
-static boolean_t icmp_param_register(IDP *ndp, icmpparam_t *icmppa, int cnt);
-static int	icmp_param_set(queue_t *q, mblk_t *mp, char *value,
-		    caddr_t cp, cred_t *cr);
 static mblk_t	*icmp_prepend_hdr(conn_t *, ip_xmit_attr_t *, const ip_pkt_t *,
     const in6_addr_t *, const in6_addr_t *, uint32_t, mblk_t *, int *);
 static mblk_t	*icmp_prepend_header_template(conn_t *, ip_xmit_attr_t *,
@@ -219,33 +215,69 @@
 };
 
 /*
- * Table of ND variables supported by icmp.  These are loaded into is_nd
- * when the stack instance is created.
  * All of these are alterable, within the min/max values given, at run time.
+ *
+ * Note: All those tunables which do not start with "icmp_" are Committed and
+ * therefore are public. See PSARC 2009/306.
  */
-static icmpparam_t	icmp_param_arr[] = {
-	/* min	max	value	name */
-	{ 0,	128,	32,	"icmp_wroff_extra" },
-	{ 1,	255,	255,	"icmp_ipv4_ttl" },
-	{ 0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS,	"icmp_ipv6_hoplimit"},
-	{ 0,	1,	1,	"icmp_bsd_compat" },
-	{ 4096,	65536,	8192,	"icmp_xmit_hiwat"},
-	{ 0,	65536,	1024,	"icmp_xmit_lowat"},
-	{ 4096,	65536,	8192,	"icmp_recv_hiwat"},
-	{ 65536, 1024*1024*1024, 256*1024,	"icmp_max_buf"},
-	{ 0,	1,	0,	"icmp_pmtu_discovery" },
-	{ 0,	1,	0,	"icmp_sendto_ignerr" },
+static mod_prop_info_t icmp_propinfo_tbl[] = {
+	/* tunable - 0 */
+	{ "icmp_wroff_extra", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 128, 32}, {32} },
+
+	{ "icmp_ipv4_ttl", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, 255}, {255} },
+
+	{ "icmp_ipv6_hoplimit", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS},
+	    {IPV6_DEFAULT_HOPS} },
+
+	{ "icmp_bsd_compat", MOD_PROTO_RAWIP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "send_maxbuf", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {4096, 65536, 8192}, {8192} },
+
+	{ "icmp_xmit_lowat", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 65536, 1024}, {1024} },
+
+	{ "recv_maxbuf", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {4096, 65536, 8192}, {8192} },
+
+	{ "icmp_max_buf", MOD_PROTO_RAWIP,
+	    mod_set_uint32, mod_get_uint32,
+	    {65536, 1024*1024*1024, 256*1024}, {256 * 1024} },
+
+	{ "icmp_pmtu_discovery", MOD_PROTO_RAWIP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "icmp_sendto_ignerr", MOD_PROTO_RAWIP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "?", MOD_PROTO_RAWIP, NULL, mod_get_allprop, {0}, {0} },
+
+	{ NULL, 0, NULL, NULL, {0}, {0} }
 };
-#define	is_wroff_extra			is_param_arr[0].icmp_param_value
-#define	is_ipv4_ttl			is_param_arr[1].icmp_param_value
-#define	is_ipv6_hoplimit		is_param_arr[2].icmp_param_value
-#define	is_bsd_compat			is_param_arr[3].icmp_param_value
-#define	is_xmit_hiwat			is_param_arr[4].icmp_param_value
-#define	is_xmit_lowat			is_param_arr[5].icmp_param_value
-#define	is_recv_hiwat			is_param_arr[6].icmp_param_value
-#define	is_max_buf			is_param_arr[7].icmp_param_value
-#define	is_pmtu_discovery		is_param_arr[8].icmp_param_value
-#define	is_sendto_ignerr		is_param_arr[9].icmp_param_value
+
+#define	is_wroff_extra			is_propinfo_tbl[0].prop_cur_uval
+#define	is_ipv4_ttl			is_propinfo_tbl[1].prop_cur_uval
+#define	is_ipv6_hoplimit		is_propinfo_tbl[2].prop_cur_uval
+#define	is_bsd_compat			is_propinfo_tbl[3].prop_cur_bval
+#define	is_xmit_hiwat			is_propinfo_tbl[4].prop_cur_uval
+#define	is_xmit_lowat			is_propinfo_tbl[5].prop_cur_uval
+#define	is_recv_hiwat			is_propinfo_tbl[6].prop_cur_uval
+#define	is_max_buf			is_propinfo_tbl[7].prop_cur_uval
+#define	is_pmtu_discovery		is_propinfo_tbl[8].prop_cur_bval
+#define	is_sendto_ignerr		is_propinfo_tbl[9].prop_cur_bval
 
 typedef union T_primitives *t_primp_t;
 
@@ -2423,63 +2455,6 @@
 	return (0);
 }
 
-/*
- * This routine retrieves the value of an ND variable in a icmpparam_t
- * structure.  It is called through nd_getset when a user reads the
- * variable.
- */
-/* ARGSUSED */
-static int
-icmp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	icmpparam_t	*icmppa = (icmpparam_t *)cp;
-
-	(void) mi_mpprintf(mp, "%d", icmppa->icmp_param_value);
-	return (0);
-}
-
-/*
- * Walk through the param array specified registering each element with the
- * named dispatch (ND) handler.
- */
-static boolean_t
-icmp_param_register(IDP *ndp, icmpparam_t *icmppa, int cnt)
-{
-	for (; cnt-- > 0; icmppa++) {
-		if (icmppa->icmp_param_name && icmppa->icmp_param_name[0]) {
-			if (!nd_load(ndp, icmppa->icmp_param_name,
-			    icmp_param_get, icmp_param_set,
-			    (caddr_t)icmppa)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-	return (B_TRUE);
-}
-
-/* This routine sets an ND variable in a icmpparam_t structure. */
-/* ARGSUSED */
-static int
-icmp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
-{
-	long		new_value;
-	icmpparam_t	*icmppa = (icmpparam_t *)cp;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * required bounds.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < icmppa->icmp_param_min ||
-	    new_value > icmppa->icmp_param_max) {
-		return (EINVAL);
-	}
-	/* Set the new value */
-	icmppa->icmp_param_value = new_value;
-	return (0);
-}
-
 static mblk_t *
 icmp_queue_fallback(icmp_t *icmp, mblk_t *mp)
 {
@@ -4706,7 +4681,6 @@
 	struct iocblk *iocp;
 	conn_t	*connp = Q_TO_CONN(q);
 	icmp_t	*icmp = connp->conn_icmp;
-	icmp_stack_t *is = icmp->icmp_is;
 	cred_t *cr;
 
 	switch (mp->b_datap->db_type) {
@@ -4837,14 +4811,6 @@
 			mi_copyin(q, mp, NULL,
 			    SIZEOF_STRUCT(strbuf, iocp->ioc_flag));
 			return;
-		case ND_SET:
-			/* nd_getset performs the necessary checking */
-		case ND_GET:
-			if (nd_getset(q, is->is_nd, mp)) {
-				qreply(q, mp);
-				return;
-			}
-			break;
 		default:
 			break;
 		}
@@ -4990,19 +4956,17 @@
 rawip_stack_init(netstackid_t stackid, netstack_t *ns)
 {
 	icmp_stack_t	*is;
-	icmpparam_t	*pa;
 	int		error = 0;
+	size_t		arrsz;
 	major_t		major;
 
 	is = (icmp_stack_t *)kmem_zalloc(sizeof (*is), KM_SLEEP);
 	is->is_netstack = ns;
 
-	pa = (icmpparam_t *)kmem_alloc(sizeof (icmp_param_arr), KM_SLEEP);
-	is->is_param_arr = pa;
-	bcopy(icmp_param_arr, is->is_param_arr, sizeof (icmp_param_arr));
-
-	(void) icmp_param_register(&is->is_nd,
-	    is->is_param_arr, A_CNT(icmp_param_arr));
+	arrsz = sizeof (icmp_propinfo_tbl);
+	is->is_propinfo_tbl = (mod_prop_info_t *)kmem_alloc(arrsz, KM_SLEEP);
+	bcopy(icmp_propinfo_tbl, is->is_propinfo_tbl, arrsz);
+
 	is->is_ksp = rawip_kstat_init(stackid);
 
 	major = mod_name_to_major(INET_NAME);
@@ -5019,9 +4983,8 @@
 {
 	icmp_stack_t *is = (icmp_stack_t *)arg;
 
-	nd_free(&is->is_nd);
-	kmem_free(is->is_param_arr, sizeof (icmp_param_arr));
-	is->is_param_arr = NULL;
+	kmem_free(is->is_propinfo_tbl, sizeof (icmp_propinfo_tbl));
+	is->is_propinfo_tbl = NULL;
 
 	rawip_kstat_fini(stackid, is->is_ksp);
 	is->is_ksp = NULL;
@@ -5599,8 +5562,6 @@
 	}
 
 	switch (cmd) {
-	case ND_SET:
-	case ND_GET:
 	case _SIOCSOCKFALLBACK:
 	case TI_GETPEERNAME:
 	case TI_GETMYNAME:
--- a/usr/src/uts/common/inet/ip/igmp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/igmp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -61,6 +61,7 @@
 #include <inet/common.h>
 #include <inet/mi.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
 #include <inet/ip_multi.h>
--- a/usr/src/uts/common/inet/ip/ip.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip.c	Fri Mar 26 17:53:11 2010 -0400
@@ -299,11 +299,6 @@
  * - phyint_lock: This is a per phyint mutex lock. Protects just the
  *   phyint_flags
  *
- * - ip_g_nd_lock: This is a global reader/writer lock.
- *   Any call to nd_load to load a new parameter to the ND table must hold the
- *   lock as writer. ND_GET/ND_SET routines that read the ND table hold the lock
- *   as reader.
- *
  * - ip_addr_avail_lock: This is used to ensure the uniqueness of IP addresses.
  *   This lock is held in ipif_up_done and the ipif is marked IPIF_UP and the
  *   uniqueness check also done atomically.
@@ -662,9 +657,6 @@
  */
 uint_t ip_max_frag_dups = 10;
 
-/* RFC 1122 Conformance */
-#define	IP_FORWARD_DEFAULT	IP_FORWARD_NEVER
-
 static int	ip_open(queue_t *q, dev_t *devp, int flag, int sflag,
 		    cred_t *credp, boolean_t isv6);
 static mblk_t	*ip_xmit_attach_llhdr(mblk_t *, nce_t *);
@@ -691,11 +683,6 @@
 static void	ip_lrput(queue_t *, mblk_t *);
 ipaddr_t	ip_net_mask(ipaddr_t);
 char		*ip_nv_lookup(nv_t *, int);
-static int	ip_param_get(queue_t *, mblk_t *, caddr_t, cred_t *);
-static int	ip_param_generic_get(queue_t *, mblk_t *, caddr_t, cred_t *);
-static boolean_t	ip_param_register(IDP *ndp, ipparam_t *, size_t,
-    ipndp_t *, size_t);
-static int	ip_param_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
 void	ip_rput(queue_t *, mblk_t *);
 static void	ip_rput_dlpi_writer(ipsq_t *dummy_sq, queue_t *q, mblk_t *mp,
 		    void *dummy_arg);
@@ -749,20 +736,11 @@
 static void	ip_stack_shutdown(netstackid_t stackid, void *arg);
 static void	ip_stack_fini(netstackid_t stackid, void *arg);
 
-static int	ip_forward_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
-
 static int	ip_multirt_apply_membership(int (*fn)(conn_t *, boolean_t,
     const in6_addr_t *, ipaddr_t, uint_t, mcast_record_t, const in6_addr_t *),
     ire_t *, conn_t *, boolean_t, const in6_addr_t *,  mcast_record_t,
     const in6_addr_t *);
 
-static int	ip_cgtp_filter_get(queue_t *, mblk_t *, caddr_t, cred_t *);
-static int	ip_cgtp_filter_set(queue_t *, mblk_t *, char *,
-    caddr_t, cred_t *);
-static int	ip_input_proc_set(queue_t *q, mblk_t *mp, char *value,
-    caddr_t cp, cred_t *cr);
-static int	ip_int_set(queue_t *, mblk_t *, char *, caddr_t,
-    cred_t *);
 static int	ip_squeue_switch(int);
 
 static void	*ip_kstat_init(netstackid_t, ip_stack_t *);
@@ -779,10 +757,6 @@
 
 ipaddr_t	ip_g_all_ones = IP_HOST_MASK;
 
-/* How long, in seconds, we allow frags to hang around. */
-#define	IP_FRAG_TIMEOUT		15
-#define	IPV6_FRAG_TIMEOUT	60
-
 static long ip_rput_pullups;
 int	dohwcksum = 1;	/* use h/w cksum if supported by the hardware */
 
@@ -797,191 +771,10 @@
 int	ip_cgtp_filter_rev = CGTP_FILTER_REV;	/* CGTP hooks version */
 
 /*
- * Named Dispatch Parameter Table.
- * All of these are alterable, within the min/max values given, at run time.
- */
-static ipparam_t	lcl_param_arr[] = {
-	/* min	max	value	name */
-	{  0,	1,	0,	"ip_respond_to_address_mask_broadcast"},
-	{  0,	1,	1,	"ip_respond_to_echo_broadcast"},
-	{  0,	1,	1,	"ip_respond_to_echo_multicast"},
-	{  0,	1,	0,	"ip_respond_to_timestamp"},
-	{  0,	1,	0,	"ip_respond_to_timestamp_broadcast"},
-	{  0,	1,	1,	"ip_send_redirects"},
-	{  0,	1,	0,	"ip_forward_directed_broadcasts"},
-	{  0,	10,	0,	"ip_mrtdebug"},
-	{  1,	8,	3,	"ip_ire_reclaim_fraction" },
-	{  1,	8,	3,	"ip_nce_reclaim_fraction" },
-	{  1,	8,	3,	"ip_dce_reclaim_fraction" },
-	{  1,	255,	255,	"ip_def_ttl" },
-	{  0,	1,	0,	"ip_forward_src_routed"},
-	{  0,	256,	32,	"ip_wroff_extra" },
-	{  2, 999999999, 60*20, "ip_pathmtu_interval" },	/* In seconds */
-	{  8,	65536,  64,	"ip_icmp_return_data_bytes" },
-	{  0,	1,	1,	"ip_path_mtu_discovery" },
-	{ 68,	65535,	576,	"ip_pmtu_min" },
-	{  0,	1,	0,	"ip_ignore_redirect" },
-	{  0,	1,	0,	"ip_arp_icmp_error" },
-	{  1,	254,	1,	"ip_broadcast_ttl" },
-	{  0,	99999,	100,	"ip_icmp_err_interval" },
-	{  1,	99999,	10,	"ip_icmp_err_burst" },
-	{  0,	999999999,	1000000, "ip_reass_queue_bytes" },
-	/*
-	 * See comments for ip_strict_src_multihoming for an explanation
-	 * of the semantics of ip_strict_dst_multihoming
-	 */
-	{  0,	1,	0,	"ip_strict_dst_multihoming" },
-	{  1,	MAX_ADDRS_PER_IF,	256,	"ip_addrs_per_if"},
-	{  0,	1,	0,	"ipsec_override_persocket_policy" },
-	{  0,	1,	1,	"icmp_accept_clear_messages" },
-	{  0,	1,	1,	"igmp_accept_clear_messages" },
-	{  2,	999999999, ND_DELAY_FIRST_PROBE_TIME,
-				"ip_ndp_delay_first_probe_time"},
-	{  1,	999999999, ND_MAX_UNICAST_SOLICIT,
-				"ip_ndp_max_unicast_solicit"},
-	{  1,	255,	IPV6_MAX_HOPS,	"ip6_def_hops" },
-	{  8,	IPV6_MIN_MTU,	IPV6_MIN_MTU, "ip6_icmp_return_data_bytes" },
-	{  0,	1,	0,	"ip6_forward_src_routed"},
-	{  0,	1,	1,	"ip6_respond_to_echo_multicast"},
-	{  0,	1,	1,	"ip6_send_redirects"},
-	{  0,	1,	0,	"ip6_ignore_redirect" },
-	/*
-	 * See comments for ip6_strict_src_multihoming for an explanation
-	 * of the semantics of ip6_strict_dst_multihoming
-	 */
-	{  0,	1,	0,	"ip6_strict_dst_multihoming" },
-
-	{  0,	2,	2,	"ip_src_check" },
-
-	{  0,	999999,	1000,	"ipsec_policy_log_interval" },
-
-	{  0,	1,	1,	"pim_accept_clear_messages" },
-	{  1000, 20000,	2000,	"ip_ndp_unsolicit_interval" },
-	{  1,	20,	3,	"ip_ndp_unsolicit_count" },
-	{  0,	1,	1,	"ip6_ignore_home_address_opt" },
-	{  0,	15,	0,	"ip_policy_mask" },
-	{  0,	2,	2,	"ip_ecmp_behavior" },
-	{  0,	255,	1,	"ip_multirt_ttl" },
-	{  0,	3600,	60,	"ip_ire_badcnt_lifetime" },	/* In seconds */
-	{  0,	999999,	60*60*24, "ip_max_temp_idle" },
-	{  0,	1000,	1,	"ip_max_temp_defend" },
-	/*
-	 * when a conflict of an active address is detected,
-	 * defend up to ip_max_defend times, within any
-	 * ip_defend_interval span.
-	 */
-	{  0,	1000,	3,	"ip_max_defend" },
-	{  0,	999999,	30,	"ip_defend_interval" },
-	{  0,	3600000, 300000, "ip_dup_recovery" },
-	{  0,	1,	1,	"ip_restrict_interzone_loopback" },
-	{  0,	1,	1,	"ip_lso_outbound" },
-	{  IGMP_V1_ROUTER, IGMP_V3_ROUTER, IGMP_V3_ROUTER, "igmp_max_version" },
-	{  MLD_V1_ROUTER, MLD_V2_ROUTER, MLD_V2_ROUTER, "mld_max_version" },
-#ifdef DEBUG
-	{  0,	1,	0,	"ip6_drop_inbound_icmpv6" },
-#else
-	{  0,	0,	0,	"" },
-#endif
-	/* delay before sending first probe: */
-	{  0,	20000,	1000,	"arp_probe_delay" },
-	{  0,	20000,	100,	"arp_fastprobe_delay" },
-	/* interval at which DAD probes are sent: */
-	{ 10,	20000,	1500,	"arp_probe_interval" },
-	{ 10,	20000,	150,	"arp_fastprobe_interval" },
-	/* setting probe count to 0 will disable ARP probing for DAD. */
-	{  0,	20,	3,	"arp_probe_count" },
-	{  0,	20,	3,	"arp_fastprobe_count" },
-
-	{  0,	3600000, 15000,	"ipv4_dad_announce_interval"},
-	{  0,	3600000, 15000,	"ipv6_dad_announce_interval"},
-	/*
-	 * Rate limiting parameters for DAD defense used in
-	 * ill_defend_rate_limit():
-	 * defend_rate : pkts/hour permitted
-	 * defend_interval : time that can elapse before we send out a
-	 *			DAD defense.
-	 * defend_period: denominator for defend_rate (in seconds).
-	 */
-	{  0,	3600000, 300000,	"arp_defend_interval"},
-	{  0,	20000, 100,		"arp_defend_rate"},
-	{  0,	3600000, 300000,	"ndp_defend_interval"},
-	{  0,	20000, 100,		"ndp_defend_rate"},
-	{  5,	86400,	3600,		"arp_defend_period"},
-	{  5,	86400,	3600,		"ndp_defend_period"},
-	{  0,	1,	1,		"ipv4_icmp_return_pmtu" },
-	{  0,	1,	1,		"ipv6_icmp_return_pmtu" },
-	/*
-	 * publish count/interval values used to announce local addresses
-	 * for IPv4, IPv6.
-	 */
-	{  1,	20,	5,	"ip_arp_publish_count" },
-	{  1000, 20000, 2000,   "ip_arp_publish_interval" },
-	/*
-	 * The ip*strict_src_multihoming and ip*strict_dst_multihoming provide
-	 * a range of choices for setting strong/weak/preferred end-system
-	 * behavior. The semantics for setting these are:
-	 *
-	 * ip*_strict_dst_multihoming = 0
-	 *    weak end system model for managing ip destination addresses.
-	 *    A packet with IP dst D1 that's received on interface I1 will be
-	 *    accepted as long as D1 is one of the local addresses on
-	 *    the machine, even if D1 is not configured on I1.
-	 * ip*strict_dst_multihioming = 1
-	 *    strong end system model for managing ip destination addresses.
-	 *    A packet with IP dst D1 that's received on interface I1 will be
-	 *    accepted if, and only if, D1 is configured on I1.
-	 *
-	 * ip*strict_src_multihoming = 0
-	 *    Source agnostic route selection for outgoing packets: the
-	 *    outgoing interface for a packet will be computed using
-	 *    default algorithms for route selection, where the route
-	 *    with the longest matching prefix is chosen for the output
-	 *    unless other route selection constraints are explicitly
-	 *    specified during routing table lookup.  This may result
-	 *    in packet being sent out on interface I2 with source
-	 *    address S1, even though S1 is not a configured address on I2.
-	 * ip*strict_src_multihoming = 1
-	 *    Preferred source aware route selection for outgoing packets: for
-	 *    a packet with source S2, destination D2, the route selection
-	 *    algorithm will first attempt to find a route for the destination
-	 *    that goes out through an interface where S2 is
-	 *    configured. If such a route cannot be found, then the
-	 *    best-matching route for D2 will be selected.
-	 * ip*strict_src_multihoming = 2
-	 *    Source aware route selection for outgoing packets: a packet will
-	 *    be sent out on an interface I2 only if the src address S2 of the
-	 *    packet is a configured address on I2. In conjunction with
-	 *    the setting 'ip_strict_dst_multihoming == 1', this will result in
-	 *    the implementation of Strong ES as defined in Section 3.3.4.2 of
-	 *    RFC 1122
-	 */
-	{  0,	2,	0,	"ip_strict_src_multihoming" },
-	{  0,	2,	0,	"ip6_strict_src_multihoming" }
-};
-
-/*
- * Extended NDP table
- * The addresses for the first two are filled in to be ips_ip_g_forward
- * and ips_ipv6_forward at init time.
- */
-static ipndp_t	lcl_ndp_arr[] = {
-	/* getf			setf		data			name */
-#define	IPNDP_IP_FORWARDING_OFFSET	0
-	{  ip_param_generic_get,	ip_forward_set,	NULL,
-	    "ip_forwarding" },
-#define	IPNDP_IP6_FORWARDING_OFFSET	1
-	{  ip_param_generic_get,	ip_forward_set,	NULL,
-	    "ip6_forwarding" },
-	{ ip_param_generic_get, ip_input_proc_set,
-	    (caddr_t)&ip_squeue_enter, "ip_squeue_enter" },
-	{ ip_param_generic_get, ip_int_set,
-	    (caddr_t)&ip_squeue_fanout, "ip_squeue_fanout" },
-#define	IPNDP_CGTP_FILTER_OFFSET	4
-	{  ip_cgtp_filter_get,	ip_cgtp_filter_set, NULL,
-	    "ip_cgtp_filter" },
-	{  ip_param_generic_get, ip_int_set, (caddr_t)&ip_debug,
-	    "ip_debug" },
-};
+ * IP tunables related declarations. Definitions are in ip_tunables.c
+ */
+extern mod_prop_info_t ip_propinfo_tbl[];
+extern int ip_propinfo_count;
 
 /*
  * Table of IP ioctls encoding the various properties of the ioctl and
@@ -1324,6 +1117,12 @@
 	/* 186 */ { IPI_DONTCARE /* SIOCGSTAMP */, 0, 0, 0, NULL, NULL },
 	/* 187 */ { SIOCILB, 0, IPI_PRIV | IPI_GET_CMD, MISC_CMD,
 			ip_sioctl_ilb_cmd, NULL },
+	/* 188 */ { SIOCGETPROP, 0, IPI_GET_CMD, 0, NULL, NULL },
+	/* 189 */ { SIOCSETPROP, 0, IPI_PRIV | IPI_WR, 0, NULL, NULL},
+	/* 190 */ { SIOCGLIFDADSTATE, sizeof (struct lifreq),
+			IPI_GET_CMD, LIF_CMD, ip_sioctl_get_dadstate, NULL },
+	/* 191 */ { SIOCSLIFPREFIX, sizeof (struct lifreq), IPI_PRIV | IPI_WR,
+			LIF_CMD, ip_sioctl_prefix, ip_sioctl_prefix_restart }
 };
 
 int ip_ndx_ioctl_count = sizeof (ip_ndx_ioctl_table) / sizeof (ip_ioctl_cmd_t);
@@ -4584,18 +4383,15 @@
 	ipst->ips_ip6_kstat = NULL;
 	bzero(&ipst->ips_ip6_statistics, sizeof (ipst->ips_ip6_statistics));
 
-	nd_free(&ipst->ips_ip_g_nd);
-	kmem_free(ipst->ips_param_arr, sizeof (lcl_param_arr));
-	ipst->ips_param_arr = NULL;
-	kmem_free(ipst->ips_ndp_arr, sizeof (lcl_ndp_arr));
-	ipst->ips_ndp_arr = NULL;
+	kmem_free(ipst->ips_propinfo_tbl,
+	    ip_propinfo_count * sizeof (mod_prop_info_t));
+	ipst->ips_propinfo_tbl = NULL;
 
 	dce_stack_destroy(ipst);
 	ip_mrouter_stack_destroy(ipst);
 
 	mutex_destroy(&ipst->ips_ip_mi_lock);
 	rw_destroy(&ipst->ips_ill_g_usesrc_lock);
-	rw_destroy(&ipst->ips_ip_g_nd_lock);
 
 	ret = untimeout(ipst->ips_igmp_timeout_id);
 	if (ret == -1) {
@@ -4753,8 +4549,7 @@
 ip_stack_init(netstackid_t stackid, netstack_t *ns)
 {
 	ip_stack_t	*ipst;
-	ipparam_t	*pa;
-	ipndp_t		*na;
+	size_t		arrsz;
 	major_t		major;
 
 #ifdef NS_DEBUG
@@ -4773,7 +4568,6 @@
 	mutex_init(&ipst->ips_ndp4->ndp_g_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&ipst->ips_ndp6->ndp_g_lock, NULL, MUTEX_DEFAULT, NULL);
 
-	rw_init(&ipst->ips_ip_g_nd_lock, NULL, RW_DEFAULT, NULL);
 	mutex_init(&ipst->ips_igmp_timer_lock, NULL, MUTEX_DEFAULT, NULL);
 	ipst->ips_igmp_deferred_next = INFINITY;
 	mutex_init(&ipst->ips_mld_timer_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -4793,39 +4587,16 @@
 	ip_mrouter_stack_init(ipst);
 	dce_stack_init(ipst);
 
-	ipst->ips_ip_g_frag_timeout = IP_FRAG_TIMEOUT;
-	ipst->ips_ip_g_frag_timo_ms = IP_FRAG_TIMEOUT * 1000;
-	ipst->ips_ipv6_frag_timeout = IPV6_FRAG_TIMEOUT;
-	ipst->ips_ipv6_frag_timo_ms = IPV6_FRAG_TIMEOUT * 1000;
-
 	ipst->ips_ip_multirt_log_interval = 1000;
 
-	ipst->ips_ip_g_forward = IP_FORWARD_DEFAULT;
-	ipst->ips_ipv6_forward = IP_FORWARD_DEFAULT;
 	ipst->ips_ill_index = 1;
 
-	ipst->ips_saved_ip_g_forward = -1;
+	ipst->ips_saved_ip_forwarding = -1;
 	ipst->ips_reg_vif_num = ALL_VIFS; 	/* Index to Register vif */
 
-	pa = (ipparam_t *)kmem_alloc(sizeof (lcl_param_arr), KM_SLEEP);
-	ipst->ips_param_arr = pa;
-	bcopy(lcl_param_arr, ipst->ips_param_arr, sizeof (lcl_param_arr));
-
-	na = (ipndp_t *)kmem_alloc(sizeof (lcl_ndp_arr), KM_SLEEP);
-	ipst->ips_ndp_arr = na;
-	bcopy(lcl_ndp_arr, ipst->ips_ndp_arr, sizeof (lcl_ndp_arr));
-	ipst->ips_ndp_arr[IPNDP_IP_FORWARDING_OFFSET].ip_ndp_data =
-	    (caddr_t)&ipst->ips_ip_g_forward;
-	ipst->ips_ndp_arr[IPNDP_IP6_FORWARDING_OFFSET].ip_ndp_data =
-	    (caddr_t)&ipst->ips_ipv6_forward;
-	ASSERT(strcmp(ipst->ips_ndp_arr[IPNDP_CGTP_FILTER_OFFSET].ip_ndp_name,
-	    "ip_cgtp_filter") == 0);
-	ipst->ips_ndp_arr[IPNDP_CGTP_FILTER_OFFSET].ip_ndp_data =
-	    (caddr_t)&ipst->ips_ip_cgtp_filter;
-
-	(void) ip_param_register(&ipst->ips_ip_g_nd,
-	    ipst->ips_param_arr, A_CNT(lcl_param_arr),
-	    ipst->ips_ndp_arr, A_CNT(lcl_ndp_arr));
+	arrsz = ip_propinfo_count * sizeof (mod_prop_info_t);
+	ipst->ips_propinfo_tbl = (mod_prop_info_t *)kmem_alloc(arrsz, KM_SLEEP);
+	bcopy(ip_propinfo_tbl, ipst->ips_propinfo_tbl, arrsz);
 
 	ipst->ips_ip_mibkp = ip_kstat_init(stackid, ipst);
 	ipst->ips_icmp_mibkp = icmp_kstat_init(stackid);
@@ -6726,103 +6497,6 @@
 	return (sizeof (struct ip6_mtuinfo));
 }
 
-/* Named Dispatch routine to get a current value out of our parameter table. */
-/* ARGSUSED */
-static int
-ip_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *ioc_cr)
-{
-	ipparam_t *ippa = (ipparam_t *)cp;
-
-	(void) mi_mpprintf(mp, "%d", ippa->ip_param_value);
-	return (0);
-}
-
-/* ARGSUSED */
-static int
-ip_param_generic_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *ioc_cr)
-{
-
-	(void) mi_mpprintf(mp, "%d", *(int *)cp);
-	return (0);
-}
-
-/*
- * Set ip{,6}_forwarding values.  This means walking through all of the
- * ill's and toggling their forwarding values.
- */
-/* ARGSUSED */
-static int
-ip_forward_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *ioc_cr)
-{
-	long new_value;
-	int *forwarding_value = (int *)cp;
-	ill_t *ill;
-	boolean_t isv6;
-	ill_walk_context_t ctx;
-	ip_stack_t *ipst = CONNQ_TO_IPST(q);
-
-	isv6 = (forwarding_value == &ipst->ips_ipv6_forward);
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < 0 || new_value > 1) {
-		return (EINVAL);
-	}
-
-	*forwarding_value = new_value;
-
-	/*
-	 * Regardless of the current value of ip_forwarding, set all per-ill
-	 * values of ip_forwarding to the value being set.
-	 *
-	 * Bring all the ill's up to date with the new global value.
-	 */
-	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
-
-	if (isv6)
-		ill = ILL_START_WALK_V6(&ctx, ipst);
-	else
-		ill = ILL_START_WALK_V4(&ctx, ipst);
-
-	for (; ill != NULL; ill = ill_next(&ctx, ill))
-		(void) ill_forward_set(ill, new_value != 0);
-
-	rw_exit(&ipst->ips_ill_g_lock);
-	return (0);
-}
-
-/*
- * Walk through the param array specified registering each element with the
- * Named Dispatch handler. This is called only during init. So it is ok
- * not to acquire any locks
- */
-static boolean_t
-ip_param_register(IDP *ndp, ipparam_t *ippa, size_t ippa_cnt,
-    ipndp_t *ipnd, size_t ipnd_cnt)
-{
-	for (; ippa_cnt-- > 0; ippa++) {
-		if (ippa->ip_param_name && ippa->ip_param_name[0]) {
-			if (!nd_load(ndp, ippa->ip_param_name,
-			    ip_param_get, ip_param_set, (caddr_t)ippa)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-
-	for (; ipnd_cnt-- > 0; ipnd++) {
-		if (ipnd->ip_ndp_name && ipnd->ip_ndp_name[0]) {
-			if (!nd_load(ndp, ipnd->ip_ndp_name,
-			    ipnd->ip_ndp_getf, ipnd->ip_ndp_setf,
-			    ipnd->ip_ndp_data)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-
-	return (B_TRUE);
-}
-
 /*
  * When the src multihoming is changed from weak to [strong, preferred]
  * ip_ire_rebind_walker is called to walk the list of all ire_t entries
@@ -6832,7 +6506,7 @@
  * is selected by finding an interface route for the gateway.
  */
 /* ARGSUSED */
-static void
+void
 ip_ire_rebind_walker(ire_t *ire, void *notused)
 {
 	if (!ire->ire_unbound || ire->ire_ill != NULL)
@@ -6848,7 +6522,7 @@
  * (i.e., without RTA_IFP) back to having a NULL ire_ill.
  */
 /* ARGSUSED */
-static void
+void
 ip_ire_unbind_walker(ire_t *ire, void *notused)
 {
 	ire_t *new_ire;
@@ -6891,7 +6565,7 @@
  * The cached ixa_ire entires for all conn_t entries are marked as
  * "verify" so that they will be recomputed for the next packet.
  */
-static void
+void
 conn_ire_revalidate(conn_t *connp, void *arg)
 {
 	boolean_t isv6 = (boolean_t)arg;
@@ -6902,45 +6576,6 @@
 	connp->conn_ixa->ixa_ire_generation = IRE_GENERATION_VERIFY;
 }
 
-/* Named Dispatch routine to negotiate a new value for one of our parameters. */
-/* ARGSUSED */
-static int
-ip_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *ioc_cr)
-{
-	long		new_value;
-	ipparam_t	*ippa = (ipparam_t *)cp;
-	ip_stack_t	*ipst = CONNQ_TO_IPST(q);
-	int		strict_src4, strict_src6;
-
-	strict_src4 = ipst->ips_ip_strict_src_multihoming;
-	strict_src6 = ipst->ips_ipv6_strict_src_multihoming;
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < ippa->ip_param_min || new_value > ippa->ip_param_max) {
-		return (EINVAL);
-	}
-	ippa->ip_param_value = new_value;
-	if (ipst->ips_ip_strict_src_multihoming != strict_src4) {
-		if (strict_src4 == 0) {
-			ire_walk_v4(ip_ire_rebind_walker, NULL, ALL_ZONES,
-			    ipst);
-		} else {
-			ire_walk_v4(ip_ire_unbind_walker, NULL, ALL_ZONES,
-			    ipst);
-		}
-		ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
-	} else if (ipst->ips_ipv6_strict_src_multihoming != strict_src6) {
-		if (strict_src6 == 0) {
-			ire_walk_v6(ip_ire_rebind_walker, NULL, ALL_ZONES,
-			    ipst);
-		} else {
-			ire_walk_v4(ip_ire_unbind_walker, NULL, ALL_ZONES,
-			    ipst);
-		}
-		ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
-	}
-	return (0);
-}
-
 /*
  * Handles both IPv4 and IPv6 reassembly - doing the out-of-order cases,
  * When an ipf is passed here for the first time, if
@@ -9413,7 +9048,7 @@
 {
 	ill_t	*ill = (ill_t *)arg;
 	boolean_t frag_pending;
-	ip_stack_t	*ipst = ill->ill_ipst;
+	ip_stack_t *ipst = ill->ill_ipst;
 	time_t	timeout;
 
 	mutex_enter(&ill->ill_lock);
@@ -9426,10 +9061,8 @@
 	ill->ill_fragtimer_executing = 1;
 	mutex_exit(&ill->ill_lock);
 
-	if (ill->ill_isv6)
-		timeout = ipst->ips_ipv6_frag_timeout;
-	else
-		timeout = ipst->ips_ip_g_frag_timeout;
+	timeout = (ill->ill_isv6 ? ipst->ips_ipv6_reassembly_timeout :
+	    ipst->ips_ip_reassembly_timeout);
 
 	frag_pending = ill_frag_timeout(ill, timeout);
 
@@ -9448,7 +9081,7 @@
 void
 ill_frag_timer_start(ill_t *ill)
 {
-	ip_stack_t	*ipst = ill->ill_ipst;
+	ip_stack_t *ipst = ill->ill_ipst;
 	clock_t	timeo_ms;
 
 	ASSERT(MUTEX_HELD(&ill->ill_lock));
@@ -9469,10 +9102,9 @@
 	}
 
 	if (ill->ill_frag_timer_id == 0) {
-		if (ill->ill_isv6)
-			timeo_ms = ipst->ips_ipv6_frag_timo_ms;
-		else
-			timeo_ms = ipst->ips_ip_g_frag_timo_ms;
+		timeo_ms = (ill->ill_isv6 ? ipst->ips_ipv6_reassembly_timeout :
+		    ipst->ips_ip_reassembly_timeout) * SECONDS;
+
 		/*
 		 * The timer is neither running nor is the timeout handler
 		 * executing. Post a timeout so that ill_frag_timer will be
@@ -10000,7 +9632,7 @@
 	SET_MIB(old_ip_mib.ipDefaultTTL,
 	    (uint32_t)ipst->ips_ip_def_ttl);
 	SET_MIB(old_ip_mib.ipReasmTimeout,
-	    ipst->ips_ip_g_frag_timeout);
+	    ipst->ips_ip_reassembly_timeout);
 	SET_MIB(old_ip_mib.ipAddrEntrySize,
 	    sizeof (mib2_ipAddrEntry_t));
 	SET_MIB(old_ip_mib.ipRouteEntrySize,
@@ -10097,7 +9729,7 @@
 	ipst->ips_ip_mib.ipIfStatsIfIndex =
 	    MIB2_UNKNOWN_INTERFACE; /* Flag to netstat */
 	SET_MIB(ipst->ips_ip_mib.ipIfStatsForwarding,
-	    (ipst->ips_ip_g_forward ? 1 : 2));
+	    (ipst->ips_ip_forwarding ? 1 : 2));
 	SET_MIB(ipst->ips_ip_mib.ipIfStatsDefaultTTL,
 	    (uint32_t)ipst->ips_ip_def_ttl);
 	SET_MIB(ipst->ips_ip_mib.ipIfStatsEntrySize,
@@ -10128,7 +9760,7 @@
 		ill->ill_ip_mib->ipIfStatsIfIndex =
 		    ill->ill_phyint->phyint_ifindex;
 		SET_MIB(ill->ill_ip_mib->ipIfStatsForwarding,
-		    (ipst->ips_ip_g_forward ? 1 : 2));
+		    (ipst->ips_ip_forwarding ? 1 : 2));
 		SET_MIB(ill->ill_ip_mib->ipIfStatsDefaultTTL,
 		    (uint32_t)ipst->ips_ip_def_ttl);
 
@@ -10295,7 +9927,7 @@
 			mae.ipAdEntBcastAddr = bitval;
 			mae.ipAdEntReasmMaxSize = IP_MAXPACKET;
 			mae.ipAdEntInfo.ae_mtu = ipif->ipif_ill->ill_mtu;
-			mae.ipAdEntInfo.ae_metric  = ipif->ipif_metric;
+			mae.ipAdEntInfo.ae_metric  = ipif->ipif_ill->ill_metric;
 			mae.ipAdEntInfo.ae_broadcast_addr =
 			    ipif->ipif_brd_addr;
 			mae.ipAdEntInfo.ae_pp_dst_addr =
@@ -10398,7 +10030,8 @@
 			else
 				mae6.ipv6AddrStatus = 1;
 			mae6.ipv6AddrInfo.ae_mtu = ipif->ipif_ill->ill_mtu;
-			mae6.ipv6AddrInfo.ae_metric  = ipif->ipif_metric;
+			mae6.ipv6AddrInfo.ae_metric  =
+			    ipif->ipif_ill->ill_metric;
 			mae6.ipv6AddrInfo.ae_pp_dst_addr =
 			    ipif->ipif_v6pp_dst_addr;
 			mae6.ipv6AddrInfo.ae_flags = ipif->ipif_flags |
@@ -10980,7 +10613,7 @@
 	ipst->ips_ip6_mib.ipIfStatsIfIndex =
 	    MIB2_UNKNOWN_INTERFACE; /* Flag to netstat */
 	SET_MIB(ipst->ips_ip6_mib.ipIfStatsForwarding,
-	    ipst->ips_ipv6_forward ? 1 : 2);
+	    ipst->ips_ipv6_forwarding ? 1 : 2);
 	SET_MIB(ipst->ips_ip6_mib.ipIfStatsDefaultHopLimit,
 	    ipst->ips_ipv6_def_hops);
 	SET_MIB(ipst->ips_ip6_mib.ipIfStatsEntrySize,
@@ -11024,7 +10657,7 @@
 		ill->ill_ip_mib->ipIfStatsIfIndex =
 		    ill->ill_phyint->phyint_ifindex;
 		SET_MIB(ill->ill_ip_mib->ipIfStatsForwarding,
-		    ipst->ips_ipv6_forward ? 1 : 2);
+		    ipst->ips_ipv6_forwarding ? 1 : 2);
 		SET_MIB(ill->ill_ip_mib->ipIfStatsDefaultHopLimit,
 		    ill->ill_max_hops);
 
@@ -14014,71 +13647,6 @@
 }
 
 /*
- * Get the CGTP (multirouting) filtering status.
- * If 0, the CGTP hooks are transparent.
- */
-/* ARGSUSED */
-static int
-ip_cgtp_filter_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *ioc_cr)
-{
-	boolean_t	*ip_cgtp_filter_value = (boolean_t *)cp;
-
-	(void) mi_mpprintf(mp, "%d", (int)*ip_cgtp_filter_value);
-	return (0);
-}
-
-/*
- * Set the CGTP (multirouting) filtering status.
- * If the status is changed from active to transparent
- * or from transparent to active, forward the new status
- * to the filtering module (if loaded).
- */
-/* ARGSUSED */
-static int
-ip_cgtp_filter_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *ioc_cr)
-{
-	long		new_value;
-	boolean_t	*ip_cgtp_filter_value = (boolean_t *)cp;
-	ip_stack_t	*ipst = CONNQ_TO_IPST(q);
-
-	if (secpolicy_ip_config(ioc_cr, B_FALSE) != 0)
-		return (EPERM);
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < 0 || new_value > 1) {
-		return (EINVAL);
-	}
-
-	if ((!*ip_cgtp_filter_value) && new_value) {
-		cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
-		    ipst->ips_ip_cgtp_filter_ops == NULL ?
-		    " (module not loaded)" : "");
-	}
-	if (*ip_cgtp_filter_value && (!new_value)) {
-		cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
-		    ipst->ips_ip_cgtp_filter_ops == NULL ?
-		    " (module not loaded)" : "");
-	}
-
-	if (ipst->ips_ip_cgtp_filter_ops != NULL) {
-		int	res;
-		netstackid_t stackid;
-
-		stackid = ipst->ips_netstack->netstack_stackid;
-		res = ipst->ips_ip_cgtp_filter_ops->cfo_change_state(stackid,
-		    new_value);
-		if (res)
-			return (res);
-	}
-
-	*ip_cgtp_filter_value = (boolean_t)new_value;
-
-	ill_set_inputfn_all(ipst);
-	return (0);
-}
-
-/*
  * Return the expected CGTP hooks version number.
  */
 int
@@ -14200,47 +13768,6 @@
 	return (rval);
 }
 
-/* ARGSUSED */
-static int
-ip_input_proc_set(queue_t *q, mblk_t *mp, char *value,
-    caddr_t addr, cred_t *cr)
-{
-	int *v = (int *)addr;
-	long new_value;
-
-	if (secpolicy_net_config(cr, B_FALSE) != 0)
-		return (EPERM);
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0)
-		return (EINVAL);
-
-	ip_squeue_flag = ip_squeue_switch(new_value);
-	*v = new_value;
-	return (0);
-}
-
-/*
- * Handle ndd set of variables which require PRIV_SYS_NET_CONFIG such as
- * ip_debug.
- */
-/* ARGSUSED */
-static int
-ip_int_set(queue_t *q, mblk_t *mp, char *value,
-    caddr_t addr, cred_t *cr)
-{
-	int *v = (int *)addr;
-	long new_value;
-
-	if (secpolicy_net_config(cr, B_FALSE) != 0)
-		return (EPERM);
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0)
-		return (EINVAL);
-
-	*v = new_value;
-	return (0);
-}
-
 static void *
 ip_kstat2_init(netstackid_t stackid, ip_stat_t *ip_statisticsp)
 {
@@ -14365,7 +13892,7 @@
 
 	template.forwarding.value.ui32 = WE_ARE_FORWARDING(ipst) ? 1:2;
 	template.defaultTTL.value.ui32 = (uint32_t)ipst->ips_ip_def_ttl;
-	template.reasmTimeout.value.ui32 = ipst->ips_ip_g_frag_timeout;
+	template.reasmTimeout.value.ui32 = ipst->ips_ip_reassembly_timeout;
 	template.addrEntrySize.value.i32 = sizeof (mib2_ipAddrEntry_t);
 	template.routeEntrySize.value.i32 = sizeof (mib2_ipRouteEntry_t);
 
@@ -14437,7 +13964,7 @@
 	ipkp->outRequests.value.ui64 =		ipmib.ipIfStatsHCOutRequests;
 	ipkp->outDiscards.value.ui32 =		ipmib.ipIfStatsOutDiscards;
 	ipkp->outNoRoutes.value.ui32 =		ipmib.ipIfStatsOutNoRoutes;
-	ipkp->reasmTimeout.value.ui32 =		ipst->ips_ip_g_frag_timeout;
+	ipkp->reasmTimeout.value.ui32 =		ipst->ips_ip_reassembly_timeout;
 	ipkp->reasmReqds.value.ui32 =		ipmib.ipIfStatsReasmReqds;
 	ipkp->reasmOKs.value.ui32 =		ipmib.ipIfStatsReasmOKs;
 	ipkp->reasmFails.value.ui32 =		ipmib.ipIfStatsReasmFails;
--- a/usr/src/uts/common/inet/ip/ip6_if.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip6_if.c	Fri Mar 26 17:53:11 2010 -0400
@@ -56,6 +56,7 @@
 
 #include <inet/common.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 #include <inet/mib2.h>
 #include <inet/ip.h>
 #include <inet/ip6.h>
@@ -1153,6 +1154,14 @@
 	ASSERT(IAM_WRITER_ILL(ill));
 
 	/*
+	 * If the interface was created with no link-local address
+	 * on it and the flag ILLF_NOLINKLOCAL was set, then we
+	 * dont want to update the link-local.
+	 */
+	if ((ill->ill_flags & ILLF_NOLINKLOCAL) &&
+	    IN6_IS_ADDR_UNSPECIFIED(&ipif->ipif_v6lcl_addr))
+		return;
+	/*
 	 * ill_manual_linklocal is set when the link-local address was
 	 * manually configured.
 	 */
--- a/usr/src/uts/common/inet/ip/ip6_ire.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip6_ire.c	Fri Mar 26 17:53:11 2010 -0400
@@ -54,6 +54,7 @@
 #include <inet/ip_ire.h>
 #include <inet/ipclassifier.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 #include <sys/kmem.h>
 #include <sys/zone.h>
 
--- a/usr/src/uts/common/inet/ip/ip_if.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_if.c	Fri Mar 26 17:53:11 2010 -0400
@@ -71,6 +71,7 @@
 #include <inet/common.h>   /* for various inet/mi.h and inet/nd.h needs */
 #include <inet/mi.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 #include <inet/arp.h>
 #include <inet/ip_arp.h>
 #include <inet/mib2.h>
@@ -101,6 +102,9 @@
 #include <sys/tsol/tndb.h>
 #include <sys/tsol/tnet.h>
 
+#include <inet/rawip_impl.h> /* needed for icmp_stack_t */
+#include <inet/udp_impl.h> /* needed for udp_stack_t */
+
 /* The character which tells where the ill_name ends */
 #define	IPIF_SEPARATOR_CHAR	':'
 
@@ -275,8 +279,6 @@
 
 static ill_t	ill_null;		/* Empty ILL for init. */
 char	ipif_loopback_name[] = "lo0";
-static char *ipv4_forward_suffix = ":ip_forwarding";
-static char *ipv6_forward_suffix = ":ip6_forwarding";
 
 /* These are used by all IP network modules. */
 sin6_t	sin6_null;	/* Zero address for quick clears */
@@ -483,7 +485,7 @@
 {
 	mblk_t	**mpp;
 	ipif_t	*ipif;
-	ip_stack_t	*ipst = ill->ill_ipst;
+	ip_stack_t *ipst = ill->ill_ipst;
 
 	for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) {
 		ipif_non_duplicate(ipif);
@@ -573,11 +575,6 @@
 	 */
 	(void) ill_glist_delete(ill);
 
-	rw_enter(&ipst->ips_ip_g_nd_lock, RW_WRITER);
-	if (ill->ill_ndd_name != NULL)
-		nd_unload(&ipst->ips_ip_g_nd, ill->ill_ndd_name);
-	rw_exit(&ipst->ips_ip_g_nd_lock);
-
 	if (ill->ill_frag_ptr != NULL) {
 		uint_t count;
 
@@ -2644,52 +2641,6 @@
 	ipfp[0] = ipf;
 }
 
-#define	ND_FORWARD_WARNING	"The <if>:ip*_forwarding ndd variables are " \
-	"obsolete and may be removed in a future release of Solaris.  Use " \
-	"ifconfig(1M) to manipulate the forwarding status of an interface."
-
-/*
- * For obsolete per-interface forwarding configuration;
- * called in response to ND_GET.
- */
-/* ARGSUSED */
-static int
-nd_ill_forward_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *ioc_cr)
-{
-	ill_t *ill = (ill_t *)cp;
-
-	cmn_err(CE_WARN, ND_FORWARD_WARNING);
-
-	(void) mi_mpprintf(mp, "%d", (ill->ill_flags & ILLF_ROUTER) != 0);
-	return (0);
-}
-
-/*
- * For obsolete per-interface forwarding configuration;
- * called in response to ND_SET.
- */
-/* ARGSUSED */
-static int
-nd_ill_forward_set(queue_t *q, mblk_t *mp, char *valuestr, caddr_t cp,
-    cred_t *ioc_cr)
-{
-	long value;
-	int retval;
-	ip_stack_t *ipst = CONNQ_TO_IPST(q);
-
-	cmn_err(CE_WARN, ND_FORWARD_WARNING);
-
-	if (ddi_strtol(valuestr, NULL, 10, &value) != 0 ||
-	    value < 0 || value > 1) {
-		return (EINVAL);
-	}
-
-	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
-	retval = ill_forward_set((ill_t *)cp, (value != 0));
-	rw_exit(&ipst->ips_ill_g_lock);
-	return (retval);
-}
-
 /*
  * Helper function for ill_forward_set().
  */
@@ -2788,58 +2739,6 @@
 }
 
 /*
- * Given an ill with a _valid_ name, add the ip_forwarding ndd variable
- * for this ill.  Make sure the v6/v4 question has been answered about this
- * ill.  The creation of this ndd variable is only for backwards compatibility.
- * The preferred way to control per-interface IP forwarding is through the
- * ILLF_ROUTER interface flag.
- */
-static int
-ill_set_ndd_name(ill_t *ill)
-{
-	char *suffix;
-	ip_stack_t	*ipst = ill->ill_ipst;
-
-	ASSERT(IAM_WRITER_ILL(ill));
-
-	if (ill->ill_isv6)
-		suffix = ipv6_forward_suffix;
-	else
-		suffix = ipv4_forward_suffix;
-
-	ill->ill_ndd_name = ill->ill_name + ill->ill_name_length;
-	bcopy(ill->ill_name, ill->ill_ndd_name, ill->ill_name_length - 1);
-	/*
-	 * Copies over the '\0'.
-	 * Note that strlen(suffix) is always bounded.
-	 */
-	bcopy(suffix, ill->ill_ndd_name + ill->ill_name_length - 1,
-	    strlen(suffix) + 1);
-
-	/*
-	 * Use of the nd table requires holding the reader lock.
-	 * Modifying the nd table thru nd_load/nd_unload requires
-	 * the writer lock.
-	 */
-	rw_enter(&ipst->ips_ip_g_nd_lock, RW_WRITER);
-	if (!nd_load(&ipst->ips_ip_g_nd, ill->ill_ndd_name, nd_ill_forward_get,
-	    nd_ill_forward_set, (caddr_t)ill)) {
-		/*
-		 * If the nd_load failed, it only meant that it could not
-		 * allocate a new bunch of room for further NDD expansion.
-		 * Because of that, the ill_ndd_name will be set to 0, and
-		 * this interface is at the mercy of the global ip_forwarding
-		 * variable.
-		 */
-		rw_exit(&ipst->ips_ip_g_nd_lock);
-		ill->ill_ndd_name = NULL;
-		return (ENOMEM);
-	}
-	rw_exit(&ipst->ips_ip_g_nd_lock);
-	return (0);
-}
-
-/*
  * Intializes the context structure and returns the first ill in the list
  * cuurently start_list and end_list can have values:
  * MAX_G_HEADS		Traverse both IPV4 and IPV6 lists.
@@ -3448,8 +3347,7 @@
 	 * Allocate sufficient space to contain our fragment hash table and
 	 * the device name.
 	 */
-	frag_ptr = (uchar_t *)mi_zalloc(ILL_FRAG_HASH_TBL_SIZE +
-	    2 * LIFNAMSIZ + strlen(ipv6_forward_suffix));
+	frag_ptr = (uchar_t *)mi_zalloc(ILL_FRAG_HASH_TBL_SIZE + 2 * LIFNAMSIZ);
 	if (frag_ptr == NULL) {
 		freemsg(info_mp);
 		return (ENOMEM);
@@ -5439,6 +5337,27 @@
 }
 
 /*
+ * Returns B_FALSE if the IPv4 netmask pointed by `mask' is non-contiguous.
+ * Otherwise returns B_TRUE.
+ *
+ * The netmask can be verified to be contiguous with 32 shifts and or
+ * operations. Take the contiguous mask (in host byte order) and compute
+ * 	mask | mask << 1 | mask << 2 | ... | mask << 31
+ * the result will be the same as the 'mask' for contiguous mask.
+ */
+static boolean_t
+ip_contiguous_mask(uint32_t mask)
+{
+	uint32_t	m = mask;
+	int		i;
+
+	for (i = 1; i < 32; i++)
+		m |= (mask << i);
+
+	return (m == mask);
+}
+
+/*
  * ip_rt_add is called to add an IPv4 route to the forwarding table.
  * ill is passed in to associate it with the correct interface.
  * If ire_arg is set, then we return the held IRE in that location.
@@ -5464,6 +5383,10 @@
 	if (ire_arg != NULL)
 		*ire_arg = NULL;
 
+	/* disallow non-contiguous netmasks */
+	if (!ip_contiguous_mask(ntohl(mask)))
+		return (ENOTSUP);
+
 	/*
 	 * If this is the case of RTF_HOST being set, then we set the netmask
 	 * to all ones (regardless if one was supplied).
@@ -8840,6 +8763,248 @@
 }
 
 /*
+ * helper function for ip_sioctl_getsetprop(), which does some sanity checks
+ */
+static boolean_t
+getset_ioctl_checks(mblk_t *mp)
+{
+	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
+	mblk_t		*mp1 = mp->b_cont;
+	mod_ioc_prop_t	*pioc;
+	uint_t		flags;
+	uint_t		pioc_size;
+
+	/* do sanity checks on various arguments */
+	if (mp1 == NULL || iocp->ioc_count == 0 ||
+	    iocp->ioc_count == TRANSPARENT) {
+		return (B_FALSE);
+	}
+	if (msgdsize(mp1) < iocp->ioc_count) {
+		if (!pullupmsg(mp1, iocp->ioc_count))
+			return (B_FALSE);
+	}
+
+	pioc = (mod_ioc_prop_t *)mp1->b_rptr;
+
+	/* sanity checks on mpr_valsize */
+	pioc_size = sizeof (mod_ioc_prop_t);
+	if (pioc->mpr_valsize != 0)
+		pioc_size += pioc->mpr_valsize - 1;
+
+	if (iocp->ioc_count != pioc_size)
+		return (B_FALSE);
+
+	flags = pioc->mpr_flags;
+	if (iocp->ioc_cmd == SIOCSETPROP) {
+		/*
+		 * One can either reset the value to it's default value or
+		 * change the current value or append/remove the value from
+		 * a multi-valued properties.
+		 */
+		if ((flags & MOD_PROP_DEFAULT) != MOD_PROP_DEFAULT &&
+		    flags != MOD_PROP_ACTIVE &&
+		    flags != (MOD_PROP_ACTIVE|MOD_PROP_APPEND) &&
+		    flags != (MOD_PROP_ACTIVE|MOD_PROP_REMOVE))
+			return (B_FALSE);
+	} else {
+		ASSERT(iocp->ioc_cmd == SIOCGETPROP);
+
+		/*
+		 * One can retrieve only one kind of property information
+		 * at a time.
+		 */
+		if ((flags & MOD_PROP_ACTIVE) != MOD_PROP_ACTIVE &&
+		    (flags & MOD_PROP_DEFAULT) != MOD_PROP_DEFAULT &&
+		    (flags & MOD_PROP_POSSIBLE) != MOD_PROP_POSSIBLE &&
+		    (flags & MOD_PROP_PERM) != MOD_PROP_PERM)
+			return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * process the SIOC{SET|GET}PROP ioctl's
+ */
+/* ARGSUSED */
+static void
+ip_sioctl_getsetprop(queue_t *q, mblk_t *mp)
+{
+	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
+	mblk_t		*mp1 = mp->b_cont;
+	mod_ioc_prop_t	*pioc;
+	mod_prop_info_t *ptbl = NULL, *pinfo = NULL;
+	ip_stack_t	*ipst;
+	icmp_stack_t	*is;
+	tcp_stack_t	*tcps;
+	sctp_stack_t	*sctps;
+	udp_stack_t	*us;
+	netstack_t	*stack;
+	void		*cbarg;
+	cred_t		*cr;
+	boolean_t 	set;
+	int		err;
+
+	ASSERT(q->q_next == NULL);
+	ASSERT(CONN_Q(q));
+
+	if (!getset_ioctl_checks(mp)) {
+		miocnak(q, mp, 0, EINVAL);
+		return;
+	}
+	ipst = CONNQ_TO_IPST(q);
+	stack = ipst->ips_netstack;
+	pioc = (mod_ioc_prop_t *)mp1->b_rptr;
+
+	switch (pioc->mpr_proto) {
+	case MOD_PROTO_IP:
+	case MOD_PROTO_IPV4:
+	case MOD_PROTO_IPV6:
+		ptbl = ipst->ips_propinfo_tbl;
+		cbarg = ipst;
+		break;
+	case MOD_PROTO_RAWIP:
+		is = stack->netstack_icmp;
+		ptbl = is->is_propinfo_tbl;
+		cbarg = is;
+		break;
+	case MOD_PROTO_TCP:
+		tcps = stack->netstack_tcp;
+		ptbl = tcps->tcps_propinfo_tbl;
+		cbarg = tcps;
+		break;
+	case MOD_PROTO_UDP:
+		us = stack->netstack_udp;
+		ptbl = us->us_propinfo_tbl;
+		cbarg = us;
+		break;
+	case MOD_PROTO_SCTP:
+		sctps = stack->netstack_sctp;
+		ptbl = sctps->sctps_propinfo_tbl;
+		cbarg = sctps;
+		break;
+	default:
+		miocnak(q, mp, 0, EINVAL);
+		return;
+	}
+
+	/* search for given property in respective protocol propinfo table */
+	for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
+		if (strcmp(pinfo->mpi_name, pioc->mpr_name) == 0 &&
+		    pinfo->mpi_proto == pioc->mpr_proto)
+			break;
+	}
+	if (pinfo->mpi_name == NULL) {
+		miocnak(q, mp, 0, ENOENT);
+		return;
+	}
+
+	set = (iocp->ioc_cmd == SIOCSETPROP) ? B_TRUE : B_FALSE;
+	if (set && pinfo->mpi_setf != NULL) {
+		cr = msg_getcred(mp, NULL);
+		if (cr == NULL)
+			cr = iocp->ioc_cr;
+		err = pinfo->mpi_setf(cbarg, cr, pinfo, pioc->mpr_ifname,
+		    pioc->mpr_val, pioc->mpr_flags);
+	} else if (!set && pinfo->mpi_getf != NULL) {
+		err = pinfo->mpi_getf(cbarg, pinfo, pioc->mpr_ifname,
+		    pioc->mpr_val, pioc->mpr_valsize, pioc->mpr_flags);
+	} else {
+		err = EPERM;
+	}
+
+	if (err != 0) {
+		miocnak(q, mp, 0, err);
+	} else {
+		if (set)
+			miocack(q, mp, 0, 0);
+		else    /* For get, we need to return back the data */
+			miocack(q, mp, iocp->ioc_count, 0);
+	}
+}
+
+/*
+ * process the legacy ND_GET, ND_SET ioctl just for {ip|ip6}_forwarding
+ * as several routing daemons have unfortunately used this 'unpublished'
+ * but well-known ioctls.
+ */
+/* ARGSUSED */
+static void
+ip_process_legacy_nddprop(queue_t *q, mblk_t *mp)
+{
+	struct iocblk	*iocp = (struct iocblk *)mp->b_rptr;
+	mblk_t		*mp1 = mp->b_cont;
+	char		*pname, *pval, *buf;
+	uint_t		bufsize, proto;
+	mod_prop_info_t *ptbl = NULL, *pinfo = NULL;
+	ip_stack_t	*ipst;
+	int		err = 0;
+
+	ASSERT(CONN_Q(q));
+	ipst = CONNQ_TO_IPST(q);
+
+	if (iocp->ioc_count == 0 || mp1 == NULL) {
+		miocnak(q, mp, 0, EINVAL);
+		return;
+	}
+
+	mp1->b_datap->db_lim[-1] = '\0';	/* Force null termination */
+	pval = buf = pname = (char *)mp1->b_rptr;
+	bufsize = MBLKL(mp1);
+
+	if (strcmp(pname, "ip_forwarding") == 0) {
+		pname = "forwarding";
+		proto = MOD_PROTO_IPV4;
+	} else if (strcmp(pname, "ip6_forwarding") == 0) {
+		pname = "forwarding";
+		proto = MOD_PROTO_IPV6;
+	} else {
+		miocnak(q, mp, 0, EINVAL);
+		return;
+	}
+
+	ptbl = ipst->ips_propinfo_tbl;
+	for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
+		if (strcmp(pinfo->mpi_name, pname) == 0 &&
+		    pinfo->mpi_proto == proto)
+			break;
+	}
+
+	ASSERT(pinfo->mpi_name != NULL);
+
+	switch (iocp->ioc_cmd) {
+	case ND_GET:
+		if ((err = pinfo->mpi_getf(ipst, pinfo, NULL, buf, bufsize,
+		    0)) == 0) {
+			miocack(q, mp, iocp->ioc_count, 0);
+			return;
+		}
+		break;
+	case ND_SET:
+		/*
+		 * buffer will have property name and value in the following
+		 * format,
+		 * <property name>'\0'<property value>'\0', extract them;
+		 */
+		while (*pval++)
+			noop;
+
+		if (!*pval || pval >= (char *)mp1->b_wptr) {
+			err = EINVAL;
+		} else if ((err = pinfo->mpi_setf(ipst, NULL, pinfo, NULL,
+		    pval, 0)) == 0) {
+			miocack(q, mp, 0, 0);
+			return;
+		}
+		break;
+	default:
+		err = EINVAL;
+		break;
+	}
+	miocnak(q, mp, 0, err);
+}
+
+/*
  * Wrapper function for resuming deferred ioctl processing
  * Used for SIOCGDSTINFO, SIOCGIP6ADDRPOLICY, SIOCGMSFILTER,
  * SIOCSMSFILTER, SIOCGIPMSFILTER, and SIOCSIPMSFILTER currently.
@@ -8972,6 +9137,7 @@
 		copyin_size = SIZEOF_STRUCT(lifsrcof, iocp->ioc_flag);
 		mi_copyin(q, mp, NULL, copyin_size);
 		return;
+
 	case SIOCGIP6ADDRPOLICY:
 		ip_sioctl_ip6addrpolicy(q, mp);
 		ip6_asp_table_refrele(ipst);
@@ -8986,6 +9152,16 @@
 		ip6_asp_table_refrele(ipst);
 		return;
 
+	case ND_SET:
+	case ND_GET:
+		ip_process_legacy_nddprop(q, mp);
+		return;
+
+	case SIOCSETPROP:
+	case SIOCGETPROP:
+		ip_sioctl_getsetprop(q, mp);
+		return;
+
 	case I_PLINK:
 	case I_PUNLINK:
 	case I_LINK:
@@ -9004,38 +9180,6 @@
 		ip_sioctl_plink(NULL, q, mp, NULL);
 		return;
 
-	case ND_GET:
-	case ND_SET:
-		/*
-		 * Use of the nd table requires holding the reader lock.
-		 * Modifying the nd table thru nd_load/nd_unload requires
-		 * the writer lock.
-		 */
-		rw_enter(&ipst->ips_ip_g_nd_lock, RW_READER);
-		if (nd_getset(q, ipst->ips_ip_g_nd, mp)) {
-			rw_exit(&ipst->ips_ip_g_nd_lock);
-
-			if (iocp->ioc_error)
-				iocp->ioc_count = 0;
-			mp->b_datap->db_type = M_IOCACK;
-			qreply(q, mp);
-			return;
-		}
-		rw_exit(&ipst->ips_ip_g_nd_lock);
-		/*
-		 * We don't understand this subioctl of ND_GET / ND_SET.
-		 * Maybe intended for some driver / module below us
-		 */
-		if (q->q_next) {
-			putnext(q, mp);
-		} else {
-			iocp->ioc_error = ENOENT;
-			mp->b_datap->db_type = M_IOCNAK;
-			iocp->ioc_count = 0;
-			qreply(q, mp);
-		}
-		return;
-
 	case IP_IOCTL:
 		ip_wput_ioctl(q, mp);
 		return;
@@ -9468,6 +9612,61 @@
 }
 
 /*
+ * Set the local interface address using the given prefix and ill_token.
+ */
+/* ARGSUSED */
+int
+ip_sioctl_prefix(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
+    ip_ioctl_cmd_t *dummy_ipip, void *dummy_ifreq)
+{
+	int err;
+	in6_addr_t v6addr;
+	sin6_t *sin6;
+	ill_t *ill;
+	int i;
+
+	ip1dbg(("ip_sioctl_prefix(%s:%u %p)\n",
+	    ipif->ipif_ill->ill_name, ipif->ipif_id, (void *)ipif));
+
+	ASSERT(IAM_WRITER_IPIF(ipif));
+
+	if (!ipif->ipif_isv6)
+		return (EINVAL);
+
+	if (sin->sin_family != AF_INET6)
+		return (EAFNOSUPPORT);
+
+	sin6 = (sin6_t *)sin;
+	v6addr = sin6->sin6_addr;
+	ill = ipif->ipif_ill;
+
+	if (IN6_IS_ADDR_UNSPECIFIED(&v6addr) ||
+	    IN6_IS_ADDR_UNSPECIFIED(&ill->ill_token))
+		return (EADDRNOTAVAIL);
+
+	for (i = 0; i < 4; i++)
+		sin6->sin6_addr.s6_addr32[i] |= ill->ill_token.s6_addr32[i];
+
+	err = ip_sioctl_addr(ipif, sin, q, mp,
+	    &ip_ndx_ioctl_table[SIOCLIFADDR_NDX], dummy_ifreq);
+	return (err);
+}
+
+/*
+ * Restart entry point to restart the address set operation after the
+ * refcounts have dropped to zero.
+ */
+/* ARGSUSED */
+int
+ip_sioctl_prefix_restart(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
+    ip_ioctl_cmd_t *ipip, void *ifreq)
+{
+	ip1dbg(("ip_sioctl_prefix_restart(%s:%u %p)\n",
+	    ipif->ipif_ill->ill_name, ipif->ipif_id, (void *)ipif));
+	return (ip_sioctl_addr_restart(ipif, sin, q, mp, ipip, ifreq));
+}
+
+/*
  * Set the local interface address.
  * Allow an address of all zero when the interface is down.
  */
@@ -9501,13 +9700,28 @@
 		/*
 		 * Enforce that true multicast interfaces have a link-local
 		 * address for logical unit 0.
+		 *
+		 * However for those ipif's for which link-local address was
+		 * not created by default, also allow setting :: as the address.
+		 * This scenario would arise, when we delete an address on ipif
+		 * with logical unit 0, we would want to set :: as the address.
 		 */
 		if (ipif->ipif_id == 0 &&
 		    (ill->ill_flags & ILLF_MULTICAST) &&
 		    !(ipif->ipif_flags & (IPIF_POINTOPOINT)) &&
 		    !(phyi->phyint_flags & (PHYI_LOOPBACK)) &&
 		    !IN6_IS_ADDR_LINKLOCAL(&v6addr)) {
-			return (EADDRNOTAVAIL);
+
+			/*
+			 * if default link-local was not created by kernel for
+			 * this ill, allow setting :: as the address on ipif:0.
+			 */
+			if (ill->ill_flags & ILLF_NOLINKLOCAL) {
+				if (!IN6_IS_ADDR_UNSPECIFIED(&v6addr))
+					return (EADDRNOTAVAIL);
+			} else {
+				return (EADDRNOTAVAIL);
+			}
 		}
 
 		/*
@@ -9532,8 +9746,9 @@
 
 		addr = sin->sin_addr.s_addr;
 
-		/* Allow 0 as the local address. */
-		if (addr != 0 && !ip_addr_ok_v4(addr, ipif->ipif_net_mask))
+		/* Allow INADDR_ANY as the local address. */
+		if (addr != INADDR_ANY &&
+		    !ip_addr_ok_v4(addr, ipif->ipif_net_mask))
 			return (EADDRNOTAVAIL);
 
 		IN6_IPADDR_TO_V4MAPPED(addr, &v6addr);
@@ -9636,8 +9851,11 @@
 	 * in this address getting automatically reconfigured from under the
 	 * administrator.
 	 */
-	if (ipif->ipif_isv6 && ipif->ipif_id == 0)
-		ill->ill_manual_linklocal = 1;
+	if (ipif->ipif_isv6 && ipif->ipif_id == 0) {
+		if (iocp == NULL || (iocp->ioc_cmd == SIOCSLIFADDR &&
+		    !IN6_IS_ADDR_UNSPECIFIED(&v6addr)))
+			ill->ill_manual_linklocal = 1;
+	}
 
 	/*
 	 * When publishing an interface address change event, we only notify
@@ -9767,8 +9985,10 @@
 			return (EAFNOSUPPORT);
 
 		addr = sin->sin_addr.s_addr;
-		if (!ip_addr_ok_v4(addr, ipif->ipif_net_mask))
+		if (addr != INADDR_ANY &&
+		    !ip_addr_ok_v4(addr, ipif->ipif_net_mask)) {
 			return (EADDRNOTAVAIL);
+		}
 
 		IN6_IPADDR_TO_V4MAPPED(addr, &v6addr);
 	}
@@ -10628,6 +10848,7 @@
 		return (EAFNOSUPPORT);
 
 	addr = sin->sin_addr.s_addr;
+
 	if (ipif->ipif_flags & IPIF_UP) {
 		/*
 		 * If we are already up, make sure the new
@@ -10704,6 +10925,8 @@
 			return (EAFNOSUPPORT);
 
 		mask = sin->sin_addr.s_addr;
+		if (!ip_contiguous_mask(ntohl(mask)))
+			return (ENOTSUP);
 		V4MASK_TO_V6(mask, v6mask);
 	}
 
@@ -10846,12 +11069,12 @@
 		struct ifreq    *ifr;
 
 		ifr = (struct ifreq *)if_req;
-		ipif->ipif_metric = ifr->ifr_metric;
+		ipif->ipif_ill->ill_metric = ifr->ifr_metric;
 	} else {
 		struct lifreq   *lifr;
 
 		lifr = (struct lifreq *)if_req;
-		ipif->ipif_metric = lifr->lifr_metric;
+		ipif->ipif_ill->ill_metric = lifr->lifr_metric;
 	}
 	return (0);
 }
@@ -10869,12 +11092,12 @@
 		struct ifreq    *ifr;
 
 		ifr = (struct ifreq *)if_req;
-		ifr->ifr_metric = ipif->ipif_metric;
+		ifr->ifr_metric = ipif->ipif_ill->ill_metric;
 	} else {
 		struct lifreq   *lifr;
 
 		lifr = (struct lifreq *)if_req;
-		lifr->lifr_metric = ipif->ipif_metric;
+		lifr->lifr_metric = ipif->ipif_ill->ill_metric;
 	}
 
 	return (0);
@@ -11542,7 +11765,6 @@
 	ASSERT(sipif->ipif_ire_type == dipif->ipif_ire_type);
 
 	dipif->ipif_flags = sipif->ipif_flags;
-	dipif->ipif_metric = sipif->ipif_metric;
 	dipif->ipif_zoneid = sipif->ipif_zoneid;
 	dipif->ipif_v6subnet = sipif->ipif_v6subnet;
 	dipif->ipif_v6lcl_addr = sipif->ipif_v6lcl_addr;
@@ -15447,6 +15669,9 @@
 	if ((new_flags & IFF_IPV6) != 0) {
 		ill->ill_flags |= ILLF_IPV6;
 		ill->ill_flags &= ~ILLF_IPV4;
+
+		if (lifr->lifr_flags & IFF_NOLINKLOCAL)
+			ill->ill_flags |= ILLF_NOLINKLOCAL;
 	}
 
 	if ((new_flags & IFF_BROADCAST) != 0)
@@ -15971,8 +16196,11 @@
 	}
 
 	usesrc_ill = ill_lookup_on_ifindex(ifindex, isv6, ipst);
-	if (usesrc_ill == NULL) {
+	if (usesrc_ill == NULL)
 		return (ENXIO);
+	if (usesrc_ill == ipif->ipif_ill) {
+		ill_refrele(usesrc_ill);
+		return (EINVAL);
 	}
 
 	ipsq = ipsq_try_enter(NULL, usesrc_ill, q, mp, ip_process_ioctl,
@@ -16076,6 +16304,27 @@
 	return (err);
 }
 
+/* ARGSUSED */
+int
+ip_sioctl_get_dadstate(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
+    ip_ioctl_cmd_t *ipip, void *if_req)
+{
+	struct lifreq	*lifr = (struct lifreq *)if_req;
+	ill_t		*ill = ipif->ipif_ill;
+
+	/*
+	 * Need a lock since IFF_UP can be set even when there are
+	 * references to the ipif.
+	 */
+	mutex_enter(&ill->ill_lock);
+	if ((ipif->ipif_flags & IPIF_UP) && ipif->ipif_addr_ready == 0)
+		lifr->lifr_dadstate = DAD_IN_PROGRESS;
+	else
+		lifr->lifr_dadstate = DAD_DONE;
+	mutex_exit(&ill->ill_lock);
+	return (0);
+}
+
 /*
  * comparison function used by avl.
  */
@@ -16355,13 +16604,6 @@
 	ip_stack_t	*ipst = ill->ill_ipst;
 	phyint_t	*phyi = ill->ill_phyint;
 
-	/* Set the obsolete NDD per-interface forwarding name. */
-	err = ill_set_ndd_name(ill);
-	if (err != 0) {
-		cmn_err(CE_WARN, "ipif_set_values: ill_set_ndd_name (%d)\n",
-		    err);
-	}
-
 	/*
 	 * Now that ill_name is set, the configuration for the IPMP
 	 * meta-interface can be performed.
@@ -16494,7 +16736,6 @@
 	 * which makes the ill globally visible and also merges it with the
 	 * other protocol instance of this phyint. The remaining work is
 	 * done after entering the ipsq which may happen sometime later.
-	 * ill_set_ndd_name occurs after the ill has been made globally visible.
 	 */
 	ipif = ill->ill_ipif;
 
@@ -16546,7 +16787,7 @@
 		 * Set the ILLF_ROUTER flag according to the global
 		 * IPv6 forwarding policy.
 		 */
-		if (ipst->ips_ipv6_forward != 0)
+		if (ipst->ips_ipv6_forwarding != 0)
 			ill->ill_flags |= ILLF_ROUTER;
 	} else if (ill->ill_flags & ILLF_IPV4) {
 		ill->ill_isv6 = B_FALSE;
@@ -16561,7 +16802,7 @@
 		 * Set the ILLF_ROUTER flag according to the global
 		 * IPv4 forwarding policy.
 		 */
-		if (ipst->ips_ip_g_forward != 0)
+		if (ipst->ips_ip_forwarding != 0)
 			ill->ill_flags |= ILLF_ROUTER;
 	}
 
--- a/usr/src/uts/common/inet/ip/ip_ire.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_ire.c	Fri Mar 26 17:53:11 2010 -0400
@@ -59,6 +59,7 @@
 #include <inet/ip_ftable.h>
 #include <inet/ip_rts.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 
 #include <inet/tcp.h>
 #include <inet/ipclassifier.h>
--- a/usr/src/uts/common/inet/ip/ip_mroute.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_mroute.c	Fri Mar 26 17:53:11 2010 -0400
@@ -65,6 +65,7 @@
 #include <inet/common.h>
 #include <inet/mi.h>
 #include <inet/nd.h>
+#include <inet/tunables.h>
 #include <inet/mib2.h>
 #include <netinet/ip6.h>
 #include <inet/ip.h>
@@ -565,8 +566,8 @@
 			(void) mi_strlog(connp->conn_rq, 1, SL_TRACE,
 			    "ip_mrouter_init: turning on forwarding");
 		}
-		ipst->ips_saved_ip_g_forward = ipst->ips_ip_g_forward;
-		ipst->ips_ip_g_forward = IP_FORWARD_ALWAYS;
+		ipst->ips_saved_ip_forwarding = ipst->ips_ip_forwarding;
+		ipst->ips_ip_forwarding = IP_FORWARD_ALWAYS;
 	}
 
 	mutex_exit(&ipst->ips_ip_g_mrouter_mutex);
@@ -620,13 +621,13 @@
 
 	mrouter = ipst->ips_ip_g_mrouter;
 
-	if (ipst->ips_saved_ip_g_forward != -1) {
+	if (ipst->ips_saved_ip_forwarding != -1) {
 		if (ipst->ips_ip_mrtdebug > 1) {
 			(void) mi_strlog(mrouter->conn_rq, 1, SL_TRACE,
 			    "ip_mrouter_done: turning off forwarding");
 		}
-		ipst->ips_ip_g_forward = ipst->ips_saved_ip_g_forward;
-		ipst->ips_saved_ip_g_forward = -1;
+		ipst->ips_ip_forwarding = ipst->ips_saved_ip_forwarding;
+		ipst->ips_saved_ip_forwarding = -1;
 	}
 
 	/*
--- a/usr/src/uts/common/inet/ip/ip_rts.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip/ip_rts.c	Fri Mar 26 17:53:11 2010 -0400
@@ -1351,7 +1351,8 @@
 	if_data->ifi_addrlen = 0;		/* media address length */
 	if_data->ifi_hdrlen = 0;		/* media header length */
 	if_data->ifi_mtu = ipif->ipif_ill->ill_mtu;	/* mtu */
-	if_data->ifi_metric = ipif->ipif_metric; /* metric (external only) */
+						/* metric (external only) */
+	if_data->ifi_metric = ipif->ipif_ill->ill_metric;
 	if_data->ifi_baudrate = 0;		/* linespeed */
 
 	if_data->ifi_ipackets = 0;		/* packets received on if */
@@ -2027,7 +2028,7 @@
 		ifam = (ifa_msghdr_t *)mp->b_rptr;
 		ifam->ifam_index =
 		    ipif->ipif_ill->ill_phyint->phyint_ifindex;
-		ifam->ifam_metric = ipif->ipif_metric;
+		ifam->ifam_metric = ipif->ipif_ill->ill_metric;
 		ifam->ifam_flags = ((cmd == RTM_NEWADDR) ? RTF_UP : 0);
 		ifam->ifam_addrs = rtm_addrs;
 	} else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/ip/ip_tunables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,820 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/ip_if.h>
+#include <inet/ip_ire.h>
+#include <inet/ipclassifier.h>
+#include <inet/ip_impl.h>
+#include <inet/tunables.h>
+#include <sys/sunddi.h>
+#include <sys/policy.h>
+
+/* How long, in seconds, we allow frags to hang around. */
+#define	IP_REASM_TIMEOUT	15
+#define	IPV6_REASM_TIMEOUT	60
+
+/*
+ * Set ip{,6}_forwarding values. If the value is being set on an ill,
+ * find the ill and set the value on it. On the other hand if we are modifying
+ * global property, modify the global value and set the value on all the ills.
+ */
+/* ARGSUSED */
+static int
+ip_set_forwarding(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	char			*end;
+	unsigned long		new_value;
+	boolean_t 		per_ill, isv6;
+	ill_walk_context_t 	ctx;
+	ill_t 			*ill;
+	ip_stack_t 		*ipst = (ip_stack_t *)cbarg;
+
+	if (flags & MOD_PROP_DEFAULT) {
+		new_value = pinfo->prop_def_bval;
+	} else {
+		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
+		    *end != '\0')
+			return (EINVAL);
+		if (new_value != B_TRUE && new_value != B_FALSE)
+			return (EINVAL);
+	}
+
+	per_ill = (ifname != NULL && ifname[0] != '\0');
+	/*
+	 * if it's not per ill then set the global property and bring all the
+	 * ills up to date with the new global value.
+	 */
+	if (!per_ill)
+		pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
+
+	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	if (isv6)
+		ill = ILL_START_WALK_V6(&ctx, ipst);
+	else
+		ill = ILL_START_WALK_V4(&ctx, ipst);
+
+	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
+		/*
+		 * if the property needs to be set on a particular
+		 * interface, look for that interface.
+		 */
+		if (per_ill && strcmp(ifname, ill->ill_name) != 0)
+			continue;
+		(void) ill_forward_set(ill, new_value != 0);
+	}
+	rw_exit(&ipst->ips_ill_g_lock);
+
+	return (0);
+}
+
+static int
+ip_get_forwarding(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *pval, uint_t pr_size, uint_t flags)
+{
+	boolean_t 		value;
+	ill_walk_context_t 	ctx;
+	ill_t 			*ill;
+	ip_stack_t 		*ipst =  (ip_stack_t *)cbarg;
+	boolean_t		get_def = (flags & MOD_PROP_DEFAULT);
+	boolean_t		get_perm = (flags & MOD_PROP_PERM);
+	boolean_t		isv6;
+	size_t			nbytes = 0;
+
+	if (get_perm) {
+		nbytes = snprintf(pval, pr_size, "%d", MOD_PROP_PERM_RW);
+		goto ret;
+	} else if (get_def) {
+		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_def_bval);
+		goto ret;
+	}
+
+	/*
+	 * if per interface value is not asked for return the current
+	 * global value
+	 */
+	if (ifname == NULL || ifname[0] == '\0') {
+		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_cur_bval);
+		goto ret;
+	}
+
+	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	if (isv6)
+		ill = ILL_START_WALK_V6(&ctx, ipst);
+	else
+		ill = ILL_START_WALK_V4(&ctx, ipst);
+	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
+		/*
+		 * if the property needs to be obtained on a particular
+		 * interface, look for that interface.
+		 */
+		if (strcmp(ifname, ill->ill_name) == 0)
+			break;
+	}
+	if (ill == NULL) {
+		rw_exit(&ipst->ips_ill_g_lock);
+		return (ENXIO);
+	}
+	value = ((ill->ill_flags & ILLF_ROUTER) ? B_TRUE : B_FALSE);
+	rw_exit(&ipst->ips_ill_g_lock);
+	nbytes = snprintf(pval, pr_size, "%d", value);
+ret:
+	if (nbytes >= pr_size)
+		return (ENOBUFS);
+	return (0);
+}
+
+/*
+ * `ip_debug' is a global variable. So, we will be modifying the global
+ * variable here.
+ */
+/* ARGSUSED */
+int
+ip_set_debug(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	char 		*end;
+	unsigned long 	new_value;
+
+	if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0)
+		return (EPERM);
+
+	if (flags & MOD_PROP_DEFAULT) {
+		ip_debug = pinfo->prop_def_uval;
+		return (0);
+	}
+
+	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
+		return (EINVAL);
+	if (new_value < pinfo->prop_min_uval ||
+	    new_value > pinfo->prop_max_uval) {
+		return (ERANGE);
+	}
+	ip_debug = (uint32_t)new_value;
+	return (0);
+}
+
+/*
+ * ip_debug is a global property. For default, permission and value range
+ * we retrieve the value from `pinfo'. However for the current value we
+ * retrieve the value from the global variable `ip_debug'
+ */
+/* ARGSUSED */
+int
+ip_get_debug(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *pval, uint_t psize, uint_t flags)
+{
+	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
+	boolean_t	get_perm = (flags & MOD_PROP_PERM);
+	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
+	size_t		nbytes;
+
+	bzero(pval, psize);
+	if (get_perm)
+		nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
+	else if (get_range)
+		nbytes = snprintf(pval, psize, "%u-%u",
+		    pinfo->prop_min_uval, pinfo->prop_max_uval);
+	else if (get_def)
+		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
+	else
+		nbytes = snprintf(pval, psize, "%u", ip_debug);
+	if (nbytes >= psize)
+		return (ENOBUFS);
+	return (0);
+}
+
+/*
+ * Set the CGTP (multirouting) filtering status. If the status is changed
+ * from active to transparent or from transparent to active, forward the
+ * new status to the filtering module (if loaded).
+ */
+/* ARGSUSED */
+static int
+ip_set_cgtp_filter(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	unsigned long	new_value;
+	ip_stack_t	*ipst = (ip_stack_t *)cbarg;
+	char		*end;
+
+	if (flags & MOD_PROP_DEFAULT) {
+		new_value = pinfo->prop_def_bval;
+	} else {
+		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
+		    *end != '\0' || new_value > 1) {
+			return (EINVAL);
+		}
+	}
+	if (!pinfo->prop_cur_bval && new_value) {
+		cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
+		    ipst->ips_ip_cgtp_filter_ops == NULL ?
+		    " (module not loaded)" : "");
+	}
+	if (pinfo->prop_cur_bval && !new_value) {
+		cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
+		    ipst->ips_ip_cgtp_filter_ops == NULL ?
+		    " (module not loaded)" : "");
+	}
+	if (ipst->ips_ip_cgtp_filter_ops != NULL) {
+		int	res;
+		netstackid_t stackid = ipst->ips_netstack->netstack_stackid;
+
+		res = ipst->ips_ip_cgtp_filter_ops->cfo_change_state(stackid,
+		    new_value);
+		if (res)
+			return (res);
+	}
+	pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
+	ill_set_inputfn_all(ipst);
+	return (0);
+}
+
+/*
+ * Retrieve the default MTU or min-max MTU range for a given interface.
+ *
+ *  -- ill_max_frag value tells us the maximum MTU that can be handled by the
+ *     datalink. This value is advertised by the driver via DLPI messages
+ *     (DL_NOTE_SDU_SIZE/DL_INFO_ACK).
+ *
+ *  -- ill_current_frag for the most link-types will be same as ill_max_frag
+ *     to begin with. However it is dynamically computed for some link-types
+ *     like tunnels, based on the tunnel PMTU.
+ *
+ *  -- ill_mtu is the user set MTU using SIOCSLIFMTU and must lie between
+ *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
+ *
+ *  -- ill_user_mtu is set by in.ndpd using SIOCSLIFLNKINFO and must lie between
+ *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
+ */
+int
+ip_get_mtu(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *pval, uint_t psize, uint_t flags)
+{
+	ill_walk_context_t 	ctx;
+	ill_t 			*ill;
+	ip_stack_t 		*ipst =  (ip_stack_t *)cbarg;
+	boolean_t		isv6;
+	uint32_t		max_mtu, def_mtu;
+	size_t			nbytes = 0;
+
+	if (!(flags & (MOD_PROP_DEFAULT|MOD_PROP_POSSIBLE)))
+		return (ENOTSUP);
+
+	if (ifname == NULL || ifname[0] == '\0')
+		return (ENOTSUP);
+
+	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
+	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
+	if (isv6)
+		ill = ILL_START_WALK_V6(&ctx, ipst);
+	else
+		ill = ILL_START_WALK_V4(&ctx, ipst);
+	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
+		if (strcmp(ifname, ill->ill_name) == 0)
+			break;
+	}
+	if (ill == NULL) {
+		rw_exit(&ipst->ips_ill_g_lock);
+		return (ENXIO);
+	}
+	max_mtu = ill->ill_max_frag;
+	def_mtu = ill->ill_current_frag;
+	rw_exit(&ipst->ips_ill_g_lock);
+
+	if (flags & MOD_PROP_DEFAULT) {
+		nbytes = snprintf(pval, psize, "%u", def_mtu);
+	} else if (flags & MOD_PROP_POSSIBLE) {
+		uint32_t	min_mtu;
+
+		min_mtu = isv6 ? IPV6_MIN_MTU : IP_MIN_MTU;
+		nbytes = snprintf(pval, psize, "%u-%u", min_mtu, max_mtu);
+	} else {
+		return (ENOTSUP);
+	}
+
+	if (nbytes >= psize)
+		return (ENOBUFS);
+	return (0);
+}
+
+/*
+ * See the comments for ip[6]_strict_src_multihoming for an explanation
+ * of the semanitcs.
+ */
+/* ARGSUSED */
+static int
+ip_set_src_multihoming(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	char 		*end;
+	unsigned long 	new_value, old_value;
+	boolean_t	isv6;
+	ip_stack_t	*ipst = (ip_stack_t *)cbarg;
+
+	old_value = pinfo->prop_cur_uval;
+
+	if (flags & MOD_PROP_DEFAULT) {
+		new_value = pinfo->prop_def_uval;
+	} else {
+		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
+		    *end != '\0')
+			return (EINVAL);
+		if (new_value < pinfo->prop_min_uval ||
+		    new_value > pinfo->prop_max_uval)
+			return (ERANGE);
+	}
+	pinfo->prop_cur_uval = new_value;
+	isv6 = (strcmp(pinfo->mpi_name, "ip6_strict_src_multihoming") == 0);
+	if (new_value != old_value) {
+		if (!isv6) {
+			if (old_value == 0) {
+				ire_walk_v4(ip_ire_rebind_walker, NULL,
+				    ALL_ZONES, ipst);
+			} else {
+				ire_walk_v4(ip_ire_unbind_walker, NULL,
+				    ALL_ZONES, ipst);
+			}
+			ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
+		} else {
+			if (old_value == 0) {
+				ire_walk_v6(ip_ire_rebind_walker, NULL,
+				    ALL_ZONES, ipst);
+			} else {
+				ire_walk_v6(ip_ire_unbind_walker, NULL,
+				    ALL_ZONES, ipst);
+			}
+			ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
+		}
+	}
+	return (0);
+}
+
+/*
+ * All of these are alterable, within the min/max values given, at run time.
+ *
+ * Note: All those tunables which do not start with "ip_" are Committed and
+ * therefore are public. See PSARC 2009/306.
+ */
+mod_prop_info_t ip_propinfo_tbl[] = {
+	/* tunable - 0 */
+	{ "ip_respond_to_address_mask_broadcast", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_respond_to_echo_broadcast", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE},  {B_TRUE} },
+
+	{ "ip_respond_to_echo_multicast", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_respond_to_timestamp", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_respond_to_timestamp_broadcast", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_send_redirects", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_forward_directed_broadcasts", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_mrtdebug", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 10, 0}, {0} },
+
+	{ "ip_ire_reclaim_fraction", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 8, 3}, {3} },
+
+	{ "ip_nce_reclaim_fraction", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 8, 3}, {3} },
+
+	/* tunable - 10 */
+	{ "ip_dce_reclaim_fraction", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 8, 3}, {3} },
+
+	{ "ttl", MOD_PROTO_IPV4,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, 255}, {255} },
+
+	{ "ip_forward_src_routed", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_wroff_extra", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 256, 32}, {32} },
+
+	/* following tunable is in seconds - a deviant! */
+	{ "ip_pathmtu_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {2, 999999999, 60*20}, {60*20} },
+
+	{ "ip_icmp_return_data_bytes", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {8, 65536, 64}, {64} },
+
+	{ "ip_path_mtu_discovery", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_pmtu_min", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {68, 65535, 576}, {576} },
+
+	{ "ip_ignore_redirect", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip_arp_icmp_error", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	/* tunable - 20 */
+	{ "ip_broadcast_ttl", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 254, 1}, {1} },
+
+	{ "ip_icmp_err_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 99999, 100}, {100} },
+
+	{ "ip_icmp_err_burst", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 99999, 10}, {10} },
+
+	{ "ip_reass_queue_bytes", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 999999999, 1000000}, {1000000} },
+
+	/*
+	 * See comments for ip_strict_src_multihoming for an explanation
+	 * of the semantics of ip_strict_dst_multihoming
+	 */
+	{ "ip_strict_dst_multihoming", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1, 0}, {0} },
+
+	{ "ip_addrs_per_if", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, MAX_ADDRS_PER_IF, 256}, {256} },
+
+	{ "ipsec_override_persocket_policy", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "icmp_accept_clear_messages", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "igmp_accept_clear_messages", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_ndp_delay_first_probe_time", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {2, 999999999, ND_DELAY_FIRST_PROBE_TIME},
+	    {ND_DELAY_FIRST_PROBE_TIME} },
+
+	/* tunable - 30 */
+	{ "ip_ndp_max_unicast_solicit", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 999999999, ND_MAX_UNICAST_SOLICIT}, {ND_MAX_UNICAST_SOLICIT} },
+
+	{ "hoplimit", MOD_PROTO_IPV6,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, IPV6_MAX_HOPS}, {IPV6_MAX_HOPS} },
+
+	{ "ip6_icmp_return_data_bytes", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {8, IPV6_MIN_MTU, IPV6_MIN_MTU}, {IPV6_MIN_MTU} },
+
+	{ "ip6_forward_src_routed", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "ip6_respond_to_echo_multicast", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip6_send_redirects", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip6_ignore_redirect", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	/*
+	 * See comments for ip6_strict_src_multihoming for an explanation
+	 * of the semantics of ip6_strict_dst_multihoming
+	 */
+	{ "ip6_strict_dst_multihoming", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1, 0}, {0} },
+
+	{ "ip_src_check", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 2, 2}, {2} },
+
+	{ "ipsec_policy_log_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 999999, 1000}, {1000} },
+
+	/* tunable - 40 */
+	{ "pim_accept_clear_messages", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_ndp_unsolicit_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1000, 20000, 2000}, {2000} },
+
+	{ "ip_ndp_unsolicit_count", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 20, 3}, {3} },
+
+	{ "ip6_ignore_home_address_opt", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_policy_mask", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 15, 0}, {0} },
+
+	{ "ip_ecmp_behavior", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 2, 2}, {2} },
+
+	{ "ip_multirt_ttl", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 255, 1}, {1} },
+
+	/* following tunable is in seconds - a deviant */
+	{ "ip_ire_badcnt_lifetime", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600, 60}, {60} },
+
+	{ "ip_max_temp_idle", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 999999, 60*60*24}, {60*60*24} },
+
+	{ "ip_max_temp_defend", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1000, 1}, {1} },
+
+	/* tunable - 50 */
+	/*
+	 * when a conflict of an active address is detected,
+	 * defend up to ip_max_defend times, within any
+	 * ip_defend_interval span.
+	 */
+	{ "ip_max_defend", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1000, 3}, {3} },
+
+	{ "ip_defend_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 999999, 30}, {30} },
+
+	{ "ip_dup_recovery", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600000, 300000}, {300000} },
+
+	{ "ip_restrict_interzone_loopback", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ip_lso_outbound", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "igmp_max_version", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {IGMP_V1_ROUTER, IGMP_V3_ROUTER, IGMP_V3_ROUTER},
+	    {IGMP_V3_ROUTER} },
+
+	{ "mld_max_version", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {MLD_V1_ROUTER, MLD_V2_ROUTER, MLD_V2_ROUTER}, {MLD_V2_ROUTER} },
+
+	{ "forwarding", MOD_PROTO_IPV4,
+	    ip_set_forwarding, ip_get_forwarding,
+	    {IP_FORWARD_NEVER}, {IP_FORWARD_NEVER} },
+
+	{ "forwarding", MOD_PROTO_IPV6,
+	    ip_set_forwarding, ip_get_forwarding,
+	    {IP_FORWARD_NEVER}, {IP_FORWARD_NEVER} },
+
+	{ "ip_reasm_timeout", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {5, 255, IP_REASM_TIMEOUT},
+	    {IP_REASM_TIMEOUT} },
+
+	/* tunable - 60 */
+	{ "ip6_reasm_timeout", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {5, 255, IPV6_REASM_TIMEOUT},
+	    {IPV6_REASM_TIMEOUT} },
+
+	{ "ip_cgtp_filter", MOD_PROTO_IP,
+	    ip_set_cgtp_filter, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	/* delay before sending first probe: */
+	{ "arp_probe_delay", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20000, 1000}, {1000} },
+
+	{ "arp_fastprobe_delay", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20000, 100}, {100} },
+
+	/* interval at which DAD probes are sent: */
+	{ "arp_probe_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10, 20000, 1500}, {1500} },
+
+	{ "arp_fastprobe_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10, 20000, 150}, {150} },
+
+	{ "arp_probe_count", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20, 3}, {3} },
+
+	{ "arp_fastprobe_count", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20, 3}, {3} },
+
+	{ "ipv4_dad_announce_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600000, 15000}, {15000} },
+
+	{ "ipv6_dad_announce_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600000, 15000}, {15000} },
+
+	/* tunable - 70 */
+	/*
+	 * Rate limiting parameters for DAD defense used in
+	 * ill_defend_rate_limit():
+	 * defend_rate : pkts/hour permitted
+	 * defend_interval : time that can elapse before we send out a
+	 *			DAD defense.
+	 * defend_period: denominator for defend_rate (in seconds).
+	 */
+	{ "arp_defend_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600000, 300000}, {300000} },
+
+	{ "arp_defend_rate", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20000, 100}, {100} },
+
+	{ "ndp_defend_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 3600000, 300000}, {300000} },
+
+	{ "ndp_defend_rate", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 20000, 100}, {100} },
+
+	{ "arp_defend_period", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {5, 86400, 3600}, {3600} },
+
+	{ "ndp_defend_period", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {5, 86400, 3600}, {3600} },
+
+	{ "ipv4_icmp_return_pmtu", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "ipv6_icmp_return_pmtu", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	/*
+	 * publish count/interval values used to announce local addresses
+	 * for IPv4, IPv6.
+	 */
+	{ "ip_arp_publish_count", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 20, 5}, {5} },
+
+	{ "ip_arp_publish_interval", MOD_PROTO_IP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1000, 20000, 2000}, {2000} },
+
+	/* tunable - 80 */
+	/*
+	 * The ip*strict_src_multihoming and ip*strict_dst_multihoming provide
+	 * a range of choices for setting strong/weak/preferred end-system
+	 * behavior. The semantics for setting these are:
+	 *
+	 * ip*_strict_dst_multihoming = 0
+	 *    weak end system model for managing ip destination addresses.
+	 *    A packet with IP dst D1 that's received on interface I1 will be
+	 *    accepted as long as D1 is one of the local addresses on
+	 *    the machine, even if D1 is not configured on I1.
+	 * ip*strict_dst_multihioming = 1
+	 *    strong end system model for managing ip destination addresses.
+	 *    A packet with IP dst D1 that's received on interface I1 will be
+	 *    accepted if, and only if, D1 is configured on I1.
+	 *
+	 * ip*strict_src_multihoming = 0
+	 *    Source agnostic route selection for outgoing packets: the
+	 *    outgoing interface for a packet will be computed using
+	 *    default algorithms for route selection, where the route
+	 *    with the longest matching prefix is chosen for the output
+	 *    unless other route selection constraints are explicitly
+	 *    specified during routing table lookup.  This may result
+	 *    in packet being sent out on interface I2 with source
+	 *    address S1, even though S1 is not a configured address on I2.
+	 * ip*strict_src_multihoming = 1
+	 *    Preferred source aware route selection for outgoing packets: for
+	 *    a packet with source S2, destination D2, the route selection
+	 *    algorithm will first attempt to find a route for the destination
+	 *    that goes out through an interface where S2 is
+	 *    configured. If such a route cannot be found, then the
+	 *    best-matching route for D2 will be selected.
+	 * ip*strict_src_multihoming = 2
+	 *    Source aware route selection for outgoing packets: a packet will
+	 *    be sent out on an interface I2 only if the src address S2 of the
+	 *    packet is a configured address on I2. In conjunction with
+	 *    the setting 'ip_strict_dst_multihoming == 1', this will result in
+	 *    the implementation of Strong ES as defined in Section 3.3.4.2 of
+	 *    RFC 1122
+	 */
+	{ "ip_strict_src_multihoming", MOD_PROTO_IP,
+	    ip_set_src_multihoming, mod_get_uint32,
+	    {0, 2, 0}, {0} },
+
+	{ "ip6_strict_src_multihoming", MOD_PROTO_IP,
+	    ip_set_src_multihoming, mod_get_uint32,
+	    {0, 2, 0}, {0} },
+
+#ifdef DEBUG
+	{ "ip6_drop_inbound_icmpv6", MOD_PROTO_IP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+#else
+	{ "", 0, NULL, NULL, {0}, {0} },
+#endif
+	{ "mtu", MOD_PROTO_IPV4, NULL, ip_get_mtu, {0}, {0} },
+
+	{ "mtu", MOD_PROTO_IPV6, NULL, ip_get_mtu, {0}, {0} },
+
+	/*
+	 * The following entry is a placeholder for `ip_debug' global
+	 * variable. Within these callback functions, we will be
+	 * setting/getting the global variable
+	 */
+	{ "ip_debug", MOD_PROTO_IP,
+	    ip_set_debug, ip_get_debug,
+	    {0, 20, 0}, {0} },
+
+	{ "?", MOD_PROTO_IP, NULL, mod_get_allprop, {0}, {0} },
+
+	{ NULL, 0, NULL, NULL, {0}, {0} }
+};
+
+int ip_propinfo_count = A_CNT(ip_propinfo_tbl);
--- a/usr/src/uts/common/inet/ip_if.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip_if.h	Fri Mar 26 17:53:11 2010 -0400
@@ -80,7 +80,7 @@
 
 #define	IFF_PHYINTINST_FLAGS	(IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP| \
     IFF_MULTICAST|IFF_ROUTER|IFF_NONUD|IFF_NORTEXCH|IFF_IPV4|IFF_IPV6| \
-    IFF_COS_ENABLED|IFF_FIXEDMTU|IFF_VRRP|IFF_NOACCEPT)
+    IFF_COS_ENABLED|IFF_FIXEDMTU|IFF_VRRP|IFF_NOACCEPT|IFF_NOLINKLOCAL)
 
 #define	IFF_LOGINT_FLAGS	(IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| \
     IFF_UNNUMBERED|IFF_DHCPRUNNING|IFF_PRIVATE|IFF_NOXMIT|IFF_NOLOCAL| \
@@ -113,6 +113,7 @@
 #define	ILLF_FIXEDMTU		IFF_FIXEDMTU	/* set with SIOCSLIFMTU */
 #define	ILLF_VRRP		IFF_VRRP	/* managed by VRRP */
 #define	ILLF_NOACCEPT		IFF_NOACCEPT	/* accept only ND messagees */
+#define	ILLF_NOLINKLOCAL	IFF_NOLINKLOCAL	/* No default linklocal */
 
 #define	IPIF_UP			IFF_UP		/* interface is up */
 #define	IPIF_BROADCAST		IFF_BROADCAST	/* broadcast address valid */
@@ -338,6 +339,11 @@
 extern int ip_siocdelrt(ipif_t *, sin_t *, queue_t *, mblk_t *,
     ip_ioctl_cmd_t *, void *);
 
+extern int ip_sioctl_prefix(ipif_t *, sin_t *, queue_t *, mblk_t *,
+    ip_ioctl_cmd_t *, void *);
+extern int ip_sioctl_prefix_restart(ipif_t *, sin_t *, queue_t *, mblk_t *,
+    ip_ioctl_cmd_t *, void *);
+
 extern int ip_sioctl_addr(ipif_t *, sin_t *, queue_t *, mblk_t *,
     ip_ioctl_cmd_t *, void *);
 extern int ip_sioctl_addr_restart(ipif_t *, sin_t *, queue_t *, mblk_t *,
@@ -470,6 +476,9 @@
 extern int ip_sioctl_get_lifsrcof(ipif_t *, sin_t *, queue_t *,
     mblk_t *, ip_ioctl_cmd_t *, void *);
 
+extern int ip_sioctl_get_dadstate(ipif_t *, sin_t *, queue_t *, mblk_t *,
+    ip_ioctl_cmd_t *, void *);
+
 extern	void	ip_sioctl_copyin_resume(ipsq_t *, queue_t *, mblk_t *, void *);
 extern	void	ip_sioctl_copyin_setup(queue_t *, mblk_t *);
 extern	ip_ioctl_cmd_t *ip_sioctl_lookup(int);
--- a/usr/src/uts/common/inet/ip_impl.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -41,6 +41,7 @@
 
 #include <sys/sdt.h>
 #include <sys/dld.h>
+#include <inet/tunables.h>
 
 #define	IP_MOD_ID		5701
 
@@ -179,6 +180,9 @@
     zoneid_t);
 extern zoneid_t	ip_get_zoneid_v6(in6_addr_t *, mblk_t *, const ill_t *,
     ip_recv_attr_t *, zoneid_t);
+extern void conn_ire_revalidate(conn_t *, void *);
+extern void ip_ire_unbind_walker(ire_t *, void *);
+extern void ip_ire_rebind_walker(ire_t *, void *);
 
 /*
  * flag passed in by IP based protocols to get a private ip stream with
--- a/usr/src/uts/common/inet/ip_stack.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/ip_stack.h	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -148,8 +148,7 @@
 
 	uint_t			ips_src_generation;	/* Both IPv4 and IPv6 */
 
-	struct ipparam_s	*ips_param_arr; 	/* ndd variable table */
-	struct ipndp_s		*ips_ndp_arr;
+	struct mod_prop_info_s	*ips_propinfo_tbl; 	/* ip tunables table */
 
 	mib2_ipIfStatsEntry_t	ips_ip_mib;	/* SNMP fixed size info */
 	mib2_icmp_t	ips_icmp_mib;
@@ -170,7 +169,6 @@
 	ip6_stat_t	ips_ip6_statistics;
 
 /* ip.c */
-	krwlock_t	ips_ip_g_nd_lock;
 	kmutex_t	ips_igmp_timer_lock;
 	kmutex_t	ips_mld_timer_lock;
 	kmutex_t	ips_ip_mi_lock;
@@ -287,14 +285,6 @@
 	/* The number of policy entries in the table */
 	uint_t		ips_ip6_asp_table_count;
 
-	int		ips_ip_g_forward;
-	int		ips_ipv6_forward;
-
-	time_t		ips_ip_g_frag_timeout;
-	clock_t		ips_ip_g_frag_timo_ms;
-	time_t		ips_ipv6_frag_timeout;
-	clock_t		ips_ipv6_frag_timo_ms;
-
 	struct conn_s	*ips_ip_g_mrouter;
 
 	/* Time since last icmp_pkt_err */
@@ -306,16 +296,17 @@
 	void		*ips_ip_g_head;	/* IP Instance Data List Head */
 	void		*ips_arp_g_head; /* ARP Instance Data List Head */
 
-	caddr_t		ips_ip_g_nd;	/* Named Dispatch List Head */
-
 	/* Multirouting stuff */
 	/* Interval (in ms) between consecutive 'bad MTU' warnings */
 	hrtime_t	ips_ip_multirt_log_interval;
 	/* Time since last warning issued. */
 	hrtime_t	ips_multirt_bad_mtu_last_time;
 
-	struct cgtp_filter_ops *ips_ip_cgtp_filter_ops;	/* CGTP hooks */
-	boolean_t	ips_ip_cgtp_filter;	/* Enable/disable CGTP hooks */
+	/*
+	 * CGTP hooks. Enabling and disabling of hooks is controlled by an
+	 * IP tunable 'ips_ip_cgtp_filter'.
+	 */
+	struct cgtp_filter_ops *ips_ip_cgtp_filter_ops;
 
 	struct ipsq_s	*ips_ipsq_g_head;
 	uint_t		ips_ill_index;	/* Used to assign interface indicies */
@@ -332,7 +323,7 @@
 	kmutex_t	ips_ip_g_mrouter_mutex;
 
 	struct mrtstat	*ips_mrtstat;	/* Stats for netstat */
-	int		ips_saved_ip_g_forward;
+	int		ips_saved_ip_forwarding;
 
 	/* numvifs is only a hint about the max interface being used. */
 	ushort_t	ips_numvifs;
--- a/usr/src/uts/common/inet/nd.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/nd.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,13 +19,11 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/systm.h>
 #include <inet/common.h>
@@ -97,25 +95,8 @@
 		valp = NULL;
 	switch (iocp->ioc_cmd) {
 	case ND_GET:
-		/*
-		 * (temporary) hack: "*valp" is size of user buffer for
-		 * copyout. If result of action routine is too big, free
-		 * excess and return ioc_rval as buffer size needed.  Return
-		 * as many mblocks as will fit, free the rest.  For backward
-		 * compatibility, assume size of original ioctl buffer if
-		 * "*valp" bad or not given.
-		 */
-		if (valp)
-			(void) ddi_strtol(valp, NULL, 10, &avail);
 		/* We overwrite the name/value with the reply data */
-		{
-			mblk_t *mp2 = mp1;
-
-			while (mp2) {
-				mp2->b_wptr = mp2->b_rptr;
-				mp2 = mp2->b_cont;
-			}
-		}
+		mp1->b_wptr = mp1->b_rptr;
 		err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr);
 		if (!err) {
 			int	size_out;
@@ -141,7 +122,7 @@
 		if (valp) {
 			if ((iocp->ioc_cr != NULL) &&
 			    ((err = secpolicy_ip_config(iocp->ioc_cr, B_FALSE))
-				    == 0)) {
+			    == 0)) {
 				err = (*nde->nde_set_pfi)(q, mp1, valp,
 				    nde->nde_data, iocp->ioc_cr);
 			}
--- a/usr/src/uts/common/inet/rawip_impl.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/rawip_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* Copyright (c) 1990 Mentat Inc. */
@@ -43,14 +43,7 @@
 #include <inet/common.h>
 #include <inet/ip.h>
 #include <inet/optcom.h>
-
-/* Named Dispatch Parameter Management Structure */
-typedef struct icmpparam_s {
-	uint_t	icmp_param_min;
-	uint_t	icmp_param_max;
-	uint_t	icmp_param_value;
-	char	*icmp_param_name;
-} icmpparam_t;
+#include <inet/tunables.h>
 
 /*
  * ICMP stack instances
@@ -58,8 +51,7 @@
 struct icmp_stack {
 	netstack_t	*is_netstack;	/* Common netstack */
 	void		*is_head;	/* Head for list of open icmps */
-	IDP		is_nd;	/* Points to table of ICMP ND variables. */
-	icmpparam_t	*is_param_arr; 	/* ndd variable table */
+	mod_prop_info_t	*is_propinfo_tbl; /* holds the icmp tunables */
 	kstat_t		*is_ksp;	/* kstats */
 	mib2_rawip_t	is_rawip_mib;	/* SNMP fixed size info */
 	ldi_ident_t	is_ldi_ident;
--- a/usr/src/uts/common/inet/sctp/sctp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -62,7 +62,6 @@
 #include <inet/mi.h>
 #include <inet/mib2.h>
 #include <inet/kstatcom.h>
-#include <inet/nd.h>
 #include <inet/optcom.h>
 #include <inet/ipclassifier.h>
 #include <inet/ipsec_impl.h>
@@ -119,6 +118,12 @@
 /* The maxiimum number of tasks for each taskq. */
 int		sctp_recvq_tq_task_max = 50;
 
+/*
+ * SCTP tunables related declarations. Definitions are in sctp_tunables.c
+ */
+extern mod_prop_info_t sctp_propinfo_tbl[];
+extern int sctp_propinfo_count;
+
 /*  sctp_t/conn_t kmem cache */
 struct kmem_cache	*sctp_conn_cache;
 
@@ -1565,6 +1570,7 @@
 sctp_stack_init(netstackid_t stackid, netstack_t *ns)
 {
 	sctp_stack_t	*sctps;
+	size_t		arrsz;
 
 	sctps = kmem_zalloc(sizeof (*sctps), KM_SLEEP);
 	sctps->sctps_netstack = ns;
@@ -1573,15 +1579,16 @@
 	mutex_init(&sctps->sctps_g_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&sctps->sctps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
 	sctps->sctps_g_num_epriv_ports = SCTP_NUM_EPRIV_PORTS;
-	sctps->sctps_g_epriv_ports[0] = 2049;
-	sctps->sctps_g_epriv_ports[1] = 4045;
+	sctps->sctps_g_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
+	sctps->sctps_g_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
 
 	/* Initialize SCTP hash arrays. */
 	sctp_hash_init(sctps);
 
-	if (!sctp_nd_init(sctps)) {
-		sctp_nd_free(sctps);
-	}
+	arrsz = sctp_propinfo_count * sizeof (mod_prop_info_t);
+	sctps->sctps_propinfo_tbl = (mod_prop_info_t *)kmem_alloc(arrsz,
+	    KM_SLEEP);
+	bcopy(sctp_propinfo_tbl, sctps->sctps_propinfo_tbl, arrsz);
 
 	/* Initialize the recvq taskq. */
 	sctp_rq_tq_init(sctps);
@@ -1630,7 +1637,9 @@
 {
 	sctp_stack_t *sctps = (sctp_stack_t *)arg;
 
-	sctp_nd_free(sctps);
+	kmem_free(sctps->sctps_propinfo_tbl,
+	    sctp_propinfo_count * sizeof (mod_prop_info_t));
+	sctps->sctps_propinfo_tbl = NULL;
 
 	/* Destroy the recvq taskqs. */
 	sctp_rq_tq_fini(sctps);
--- a/usr/src/uts/common/inet/sctp/sctp.conf	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	ident	"%Z%%M%	%I%	%E% SMI"
-
-name="sctp" parent="pseudo" instance=0;
--- a/usr/src/uts/common/inet/sctp/sctp6.conf	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	ident	"%Z%%M%	%I%	%E% SMI"
-
-name="sctp6" parent="pseudo" instance=0;
--- a/usr/src/uts/common/inet/sctp/sctp6ddi.c	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * 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]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <sys/types.h>
-#include <sys/conf.h>
-#include <sys/modctl.h>
-#include <inet/common.h>
-#include <inet/ip.h>
-
-#define	INET_NAME	"sctp6"
-#define	INET_DEVDESC	"SCTP6 device"
-#define	INET_DEVSTRTAB	sctpinfo
-#define	INET_DEVMINOR	0
-#define	INET_DEVMTFLAGS	D_MP
-
-#include "../inetddi.c"
-
-int
-_init(void)
-{
-	/*
-	 * device initialization happens when the actual code containing
-	 * module (/kernel/drv/ip) is loaded, and driven from ip_ddi_init()
-	 */
-	return (mod_install(&modlinkage));
-}
-
-int
-_fini(void)
-{
-	return (mod_remove(&modlinkage));
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -34,6 +34,7 @@
 #include <sys/zone.h>
 #include <netinet/ip6.h>
 #include <inet/optcom.h>
+#include <inet/tunables.h>
 #include <netinet/sctp.h>
 #include <inet/sctp_itf.h>
 #include "sctp_stack.h"
@@ -74,80 +75,66 @@
 	IN6_IS_ADDR_UNSPECIFIED(&(addr)))
 
 /*
- * SCTP parameters
+ * SCTP properties/tunables
  */
-/* Named Dispatch Parameter Management Structure */
-typedef struct sctpparam_s {
-	uint32_t	sctp_param_min;
-	uint32_t	sctp_param_max;
-	uint32_t	sctp_param_val;
-	char		*sctp_param_name;
-} sctpparam_t;
-
-#define	sctps_max_init_retr		sctps_params[0].sctp_param_val
-#define	sctps_max_init_retr_high	sctps_params[0].sctp_param_max
-#define	sctps_max_init_retr_low		sctps_params[0].sctp_param_min
-#define	sctps_pa_max_retr		sctps_params[1].sctp_param_val
-#define	sctps_pa_max_retr_high		sctps_params[1].sctp_param_max
-#define	sctps_pa_max_retr_low		sctps_params[1].sctp_param_min
-#define	sctps_pp_max_retr		sctps_params[2].sctp_param_val
-#define	sctps_pp_max_retr_high		sctps_params[2].sctp_param_max
-#define	sctps_pp_max_retr_low		sctps_params[2].sctp_param_min
-#define	sctps_cwnd_max_			sctps_params[3].sctp_param_val
-#define	__sctps_not_used1		sctps_params[4].sctp_param_val
-#define	sctps_smallest_nonpriv_port	sctps_params[5].sctp_param_val
-#define	sctps_ipv4_ttl			sctps_params[6].sctp_param_val
-#define	sctps_heartbeat_interval	sctps_params[7].sctp_param_val
-#define	sctps_heartbeat_interval_high	sctps_params[7].sctp_param_max
-#define	sctps_heartbeat_interval_low	sctps_params[7].sctp_param_min
-#define	sctps_initial_mtu		sctps_params[8].sctp_param_val
-#define	sctps_mtu_probe_interval	sctps_params[9].sctp_param_val
-#define	sctps_new_secret_interval	sctps_params[10].sctp_param_val
-#define	sctps_deferred_ack_interval	sctps_params[11].sctp_param_val
-#define	sctps_snd_lowat_fraction	sctps_params[12].sctp_param_val
-#define	sctps_ignore_path_mtu		sctps_params[13].sctp_param_val
-#define	sctps_initial_ssthresh		sctps_params[14].sctp_param_val
-#define	sctps_smallest_anon_port	sctps_params[15].sctp_param_val
-#define	sctps_largest_anon_port		sctps_params[16].sctp_param_val
-#define	sctps_xmit_hiwat		sctps_params[17].sctp_param_val
-#define	sctps_xmit_lowat		sctps_params[18].sctp_param_val
-#define	sctps_recv_hiwat		sctps_params[19].sctp_param_val
-#define	sctps_max_buf			sctps_params[20].sctp_param_val
-#define	sctps_rtt_updates		sctps_params[21].sctp_param_val
-#define	sctps_ipv6_hoplimit		sctps_params[22].sctp_param_val
-#define	sctps_rto_ming			sctps_params[23].sctp_param_val
-#define	sctps_rto_ming_high		sctps_params[23].sctp_param_max
-#define	sctps_rto_ming_low		sctps_params[23].sctp_param_min
-#define	sctps_rto_maxg			sctps_params[24].sctp_param_val
-#define	sctps_rto_maxg_high		sctps_params[24].sctp_param_max
-#define	sctps_rto_maxg_low		sctps_params[24].sctp_param_min
-#define	sctps_rto_initialg		sctps_params[25].sctp_param_val
-#define	sctps_rto_initialg_high		sctps_params[25].sctp_param_max
-#define	sctps_rto_initialg_low		sctps_params[25].sctp_param_min
-#define	sctps_cookie_life		sctps_params[26].sctp_param_val
-#define	sctps_cookie_life_high		sctps_params[26].sctp_param_max
-#define	sctps_cookie_life_low		sctps_params[26].sctp_param_min
-#define	sctps_max_in_streams		sctps_params[27].sctp_param_val
-#define	sctps_max_in_streams_high	sctps_params[27].sctp_param_max
-#define	sctps_max_in_streams_low	sctps_params[27].sctp_param_min
-#define	sctps_initial_out_streams	sctps_params[28].sctp_param_val
-#define	sctps_initial_out_streams_high	sctps_params[28].sctp_param_max
-#define	sctps_initial_out_streams_low	sctps_params[28].sctp_param_min
-#define	sctps_shutack_wait_bound	sctps_params[29].sctp_param_val
-#define	sctps_maxburst			sctps_params[30].sctp_param_val
-#define	sctps_addip_enabled		sctps_params[31].sctp_param_val
-#define	sctps_recv_hiwat_minmss		sctps_params[32].sctp_param_val
-#define	sctps_slow_start_initial	sctps_params[33].sctp_param_val
-#define	sctps_slow_start_after_idle	sctps_params[34].sctp_param_val
-#define	sctps_prsctp_enabled		sctps_params[35].sctp_param_val
-#define	sctps_fast_rxt_thresh		sctps_params[36].sctp_param_val
-#define	sctps_deferred_acks_max		sctps_params[37].sctp_param_val
-
-/*
- * sctp_wroff_xtra is the extra space in front of SCTP/IP header for link
- * layer header.  It has to be a multiple of 4.
- */
-#define	sctps_wroff_xtra	sctps_wroff_xtra_param->sctp_param_val
+#define	sctps_max_init_retr		sctps_propinfo_tbl[0].prop_cur_uval
+#define	sctps_max_init_retr_high	sctps_propinfo_tbl[0].prop_max_uval
+#define	sctps_max_init_retr_low		sctps_propinfo_tbl[0].prop_min_uval
+#define	sctps_pa_max_retr		sctps_propinfo_tbl[1].prop_cur_uval
+#define	sctps_pa_max_retr_high		sctps_propinfo_tbl[1].prop_max_uval
+#define	sctps_pa_max_retr_low		sctps_propinfo_tbl[1].prop_min_uval
+#define	sctps_pp_max_retr		sctps_propinfo_tbl[2].prop_cur_uval
+#define	sctps_pp_max_retr_high		sctps_propinfo_tbl[2].prop_max_uval
+#define	sctps_pp_max_retr_low		sctps_propinfo_tbl[2].prop_min_uval
+#define	sctps_cwnd_max_			sctps_propinfo_tbl[3].prop_cur_uval
+#define	sctps_smallest_nonpriv_port	sctps_propinfo_tbl[4].prop_cur_uval
+#define	sctps_ipv4_ttl			sctps_propinfo_tbl[5].prop_cur_uval
+#define	sctps_heartbeat_interval	sctps_propinfo_tbl[6].prop_cur_uval
+#define	sctps_heartbeat_interval_high	sctps_propinfo_tbl[6].prop_max_uval
+#define	sctps_heartbeat_interval_low	sctps_propinfo_tbl[6].prop_min_uval
+#define	sctps_initial_mtu		sctps_propinfo_tbl[7].prop_cur_uval
+#define	sctps_mtu_probe_interval	sctps_propinfo_tbl[8].prop_cur_uval
+#define	sctps_new_secret_interval	sctps_propinfo_tbl[9].prop_cur_uval
+#define	sctps_deferred_ack_interval	sctps_propinfo_tbl[10].prop_cur_uval
+#define	sctps_snd_lowat_fraction	sctps_propinfo_tbl[11].prop_cur_uval
+#define	sctps_ignore_path_mtu		sctps_propinfo_tbl[12].prop_cur_bval
+#define	sctps_initial_ssthresh		sctps_propinfo_tbl[13].prop_cur_uval
+#define	sctps_smallest_anon_port	sctps_propinfo_tbl[14].prop_cur_uval
+#define	sctps_largest_anon_port		sctps_propinfo_tbl[15].prop_cur_uval
+#define	sctps_xmit_hiwat		sctps_propinfo_tbl[16].prop_cur_uval
+#define	sctps_xmit_lowat		sctps_propinfo_tbl[17].prop_cur_uval
+#define	sctps_recv_hiwat		sctps_propinfo_tbl[18].prop_cur_uval
+#define	sctps_max_buf			sctps_propinfo_tbl[19].prop_cur_uval
+#define	sctps_rtt_updates		sctps_propinfo_tbl[20].prop_cur_uval
+#define	sctps_ipv6_hoplimit		sctps_propinfo_tbl[21].prop_cur_uval
+#define	sctps_rto_ming			sctps_propinfo_tbl[22].prop_cur_uval
+#define	sctps_rto_ming_high		sctps_propinfo_tbl[22].prop_max_uval
+#define	sctps_rto_ming_low		sctps_propinfo_tbl[22].prop_min_uval
+#define	sctps_rto_maxg			sctps_propinfo_tbl[23].prop_cur_uval
+#define	sctps_rto_maxg_high		sctps_propinfo_tbl[23].prop_max_uval
+#define	sctps_rto_maxg_low		sctps_propinfo_tbl[23].prop_min_uval
+#define	sctps_rto_initialg		sctps_propinfo_tbl[24].prop_cur_uval
+#define	sctps_rto_initialg_high		sctps_propinfo_tbl[24].prop_max_uval
+#define	sctps_rto_initialg_low		sctps_propinfo_tbl[24].prop_min_uval
+#define	sctps_cookie_life		sctps_propinfo_tbl[25].prop_cur_uval
+#define	sctps_cookie_life_high		sctps_propinfo_tbl[25].prop_max_uval
+#define	sctps_cookie_life_low		sctps_propinfo_tbl[25].prop_min_uval
+#define	sctps_max_in_streams		sctps_propinfo_tbl[26].prop_cur_uval
+#define	sctps_max_in_streams_high	sctps_propinfo_tbl[26].prop_max_uval
+#define	sctps_max_in_streams_low	sctps_propinfo_tbl[26].prop_min_uval
+#define	sctps_initial_out_streams	sctps_propinfo_tbl[27].prop_cur_uval
+#define	sctps_initial_out_streams_high	sctps_propinfo_tbl[27].prop_max_uval
+#define	sctps_initial_out_streams_low	sctps_propinfo_tbl[27].prop_min_uval
+#define	sctps_shutack_wait_bound	sctps_propinfo_tbl[28].prop_cur_uval
+#define	sctps_maxburst			sctps_propinfo_tbl[29].prop_cur_uval
+#define	sctps_addip_enabled		sctps_propinfo_tbl[30].prop_cur_bval
+#define	sctps_recv_hiwat_minmss		sctps_propinfo_tbl[31].prop_cur_uval
+#define	sctps_slow_start_initial	sctps_propinfo_tbl[32].prop_cur_uval
+#define	sctps_slow_start_after_idle	sctps_propinfo_tbl[33].prop_cur_uval
+#define	sctps_prsctp_enabled		sctps_propinfo_tbl[34].prop_cur_bval
+#define	sctps_fast_rxt_thresh		sctps_propinfo_tbl[35].prop_cur_uval
+#define	sctps_deferred_acks_max		sctps_propinfo_tbl[36].prop_cur_uval
+#define	sctps_wroff_xtra		sctps_propinfo_tbl[37].prop_cur_uval
 
 /*
  * Retransmission timer start and stop macro for a given faddr.
@@ -1005,9 +992,6 @@
 extern void	sctp_maxpsz_set(sctp_t *);
 extern void	sctp_move_faddr_timers(queue_t *, sctp_t *);
 
-extern void	sctp_nd_free(sctp_stack_t *);
-extern int	sctp_nd_getset(queue_t *, MBLKP);
-extern boolean_t sctp_nd_init(sctp_stack_t *);
 extern sctp_parm_hdr_t *sctp_next_parm(sctp_parm_hdr_t *, ssize_t *);
 
 extern void	sctp_ootb_shutdown_ack(mblk_t *, uint_t, ip_recv_attr_t *,
@@ -1016,7 +1000,6 @@
 extern size_t	sctp_options_param_len(const sctp_t *, int);
 extern void	sctp_output(sctp_t *, uint_t);
 
-extern boolean_t sctp_param_register(IDP *, sctpparam_t *, int, sctp_stack_t *);
 extern void	sctp_partial_delivery_event(sctp_t *);
 extern int	sctp_process_cookie(sctp_t *, sctp_chunk_hdr_t *, mblk_t *,
 		    sctp_init_chunk_t **, sctp_hdr_t *, int *, in6_addr_t *,
@@ -1081,8 +1064,6 @@
 
 extern void	sctp_validate_peer(sctp_t *);
 
-extern void	sctp_wput_ioctl(queue_t *, mblk_t *);
-
 extern int	sctp_xmit_list_clean(sctp_t *, ssize_t);
 
 extern void	sctp_zap_addrs(sctp_t *);
--- a/usr/src/uts/common/inet/sctp/sctp_ioc.c	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * 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]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/types.h>
-#include <sys/stream.h>
-#include <sys/strsubr.h>
-#include <sys/stropts.h>
-#include <sys/strsun.h>
-#define	_SUN_TPI_VERSION 2
-#include <sys/tihdr.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/errno.h>
-#include <sys/socket.h>
-#include <sys/kmem.h>
-#include <sys/random.h>
-#include <sys/policy.h>
-
-#include <netinet/in.h>
-
-#include <inet/common.h>
-#include <inet/ip.h>
-#include <inet/nd.h>
-#include <inet/ipclassifier.h>
-#include <inet/optcom.h>
-#include <inet/sctp_ip.h>
-#include "sctp_impl.h"
-
-/*
- * sctp_wput_ioctl is called by sctp_wput to handle all
- * M_IOCTL messages.
- */
-void
-sctp_wput_ioctl(queue_t *q, mblk_t *mp)
-{
-	conn_t	*connp = (conn_t *)q->q_ptr;
-	struct iocblk	*iocp;
-
-	if (connp == NULL) {
-		ip0dbg(("sctp_wput_ioctl: null conn\n"));
-		return;
-	}
-
-	iocp = (struct iocblk *)mp->b_rptr;
-	switch (iocp->ioc_cmd) {
-	case ND_SET:
-		/* sctp_nd_getset() -> nd_getset() does the checking. */
-	case ND_GET:
-		if (!sctp_nd_getset(q, mp)) {
-			break;
-		}
-		qreply(q, mp);
-		return;
-	default:
-		iocp->ioc_error = EOPNOTSUPP;
-		break;
-	}
-err_ret:
-	iocp->ioc_count = 0;
-	mp->b_datap->db_type = M_IOCNAK;
-	qreply(q, mp);
-}
-
-/*
- * A SCTP streams driver which is there just to handle ioctls on /dev/sctp.
- */
-static int sctp_str_close(queue_t *);
-static int sctp_str_open(queue_t *, dev_t *, int, int, cred_t *);
-
-static struct module_info sctp_mod_info =  {
-	5711, "sctp", 1, INFPSZ, 512, 128
-};
-
-static struct qinit sctprinit = {
-	NULL, NULL, sctp_str_open, sctp_str_close, NULL, &sctp_mod_info
-};
-
-static struct qinit sctpwinit = {
-	(pfi_t)sctp_wput, NULL, NULL, NULL, NULL, &sctp_mod_info
-};
-
-struct streamtab sctpinfo = {
-	&sctprinit, &sctpwinit
-};
-
-static int
-sctp_str_close(queue_t *q)
-{
-	conn_t	*connp = Q_TO_CONN(q);
-
-	qprocsoff(connp->conn_rq);
-
-	ASSERT(connp->conn_ref == 1);
-
-	inet_minor_free(connp->conn_minor_arena, connp->conn_dev);
-
-	q->q_ptr = WR(q)->q_ptr = NULL;
-	CONN_DEC_REF(connp);
-
-	return (0);
-}
-
-/*ARGSUSED2*/
-static int
-sctp_str_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
-{
-	conn_t 		*connp;
-	major_t		maj;
-	netstack_t	*ns;
-	zoneid_t	zoneid;
-
-	/* If the stream is already open, return immediately. */
-	if (q->q_ptr != NULL)
-		return (0);
-
-	/* If this is not a driver open, fail. */
-	if (sflag == MODOPEN)
-		return (EINVAL);
-
-	ns = netstack_find_by_cred(credp);
-	ASSERT(ns != NULL);
-
-	/*
-	 * For exclusive stacks we set the zoneid to zero
-	 * to make IP operate as if in the global zone.
-	 */
-	if (ns->netstack_stackid != GLOBAL_NETSTACKID)
-		zoneid = GLOBAL_ZONEID;
-	else
-		zoneid = crgetzoneid(credp);
-
-	/*
-	 * We are opening as a device. This is an IP client stream, and we
-	 * allocate an conn_t as the instance data.
-	 */
-	connp = ipcl_conn_create(IPCL_IPCCONN, KM_SLEEP, ns);
-
-	/*
-	 * ipcl_conn_create did a netstack_hold. Undo the hold that was
-	 * done by netstack_find_by_cred()
-	 */
-	netstack_rele(ns);
-
-	connp->conn_zoneid = zoneid;
-	connp->conn_ixa->ixa_flags |= IXAF_SET_ULP_CKSUM;
-	/* conn_allzones can not be set this early, hence no IPCL_ZONEID */
-	connp->conn_ixa->ixa_zoneid = zoneid;
-
-	connp->conn_rq = q;
-	connp->conn_wq = WR(q);
-	q->q_ptr = WR(q)->q_ptr = connp;
-
-	if ((ip_minor_arena_la != NULL) &&
-	    (connp->conn_dev = inet_minor_alloc(ip_minor_arena_la)) != 0) {
-		connp->conn_minor_arena = ip_minor_arena_la;
-	} else {
-		/*
-		 * Minor numbers in the large arena are exhausted.
-		 * Try to allocate from the small arena.
-		 */
-		if ((connp->conn_dev = inet_minor_alloc(ip_minor_arena_sa))
-		    == 0) {
-			/* CONN_DEC_REF takes care of netstack_rele() */
-			q->q_ptr = WR(q)->q_ptr = NULL;
-			CONN_DEC_REF(connp);
-			return (EBUSY);
-		}
-		connp->conn_minor_arena = ip_minor_arena_sa;
-	}
-
-	maj = getemajor(*devp);
-	*devp = makedevice(maj, (minor_t)connp->conn_dev);
-
-	/*
-	 * connp->conn_cred is crfree()ed in ipcl_conn_destroy()
-	 */
-	ASSERT(connp->conn_cred == NULL);
-	connp->conn_cred = credp;
-	crhold(connp->conn_cred);
-	connp->conn_cpid = curproc->p_pid;
-	/* Cache things in ixa without an extra refhold */
-	ASSERT(!(connp->conn_ixa->ixa_free_flags & IXA_FREE_CRED));
-	connp->conn_ixa->ixa_cred = connp->conn_cred;
-	connp->conn_ixa->ixa_cpid = connp->conn_cpid;
-	if (is_system_labeled())
-		connp->conn_ixa->ixa_tsl = crgetlabel(connp->conn_cred);
-
-	/*
-	 * Make the conn globally visible to walkers
-	 */
-	mutex_enter(&connp->conn_lock);
-	connp->conn_state_flags &= ~CONN_INCIPIENT;
-	mutex_exit(&connp->conn_lock);
-	ASSERT(connp->conn_ref == 1);
-
-	qprocson(q);
-
-	return (0);
-}
-
-
-/*
- * The SCTP write put procedure which is used only to handle ioctls.
- */
-void
-sctp_wput(queue_t *q, mblk_t *mp)
-{
-	uchar_t		*rptr;
-	t_scalar_t	type;
-
-	switch (mp->b_datap->db_type) {
-	case M_IOCTL:
-		sctp_wput_ioctl(q, mp);
-		break;
-	case M_DATA:
-		/* Should be handled in sctp_output() */
-		ASSERT(0);
-		freemsg(mp);
-		break;
-	case M_PROTO:
-	case M_PCPROTO:
-		rptr = mp->b_rptr;
-		if ((mp->b_wptr - rptr) >= sizeof (t_scalar_t)) {
-			type = ((union T_primitives *)rptr)->type;
-			/*
-			 * There is no "standard" way on how to respond
-			 * to T_CAPABILITY_REQ if a module does not
-			 * understand it.  And the current TI mod
-			 * has problems handling an error ack.  So we
-			 * catch the request here and reply with a response
-			 * which the TI mod knows how to respond to.
-			 */
-			switch (type) {
-			case T_CAPABILITY_REQ:
-				(void) putnextctl1(RD(q), M_ERROR, EPROTO);
-				break;
-			default:
-				if ((mp = mi_tpi_err_ack_alloc(mp,
-				    TNOTSUPPORT, 0)) != NULL) {
-					qreply(q, mp);
-					return;
-				}
-			}
-		}
-		/* FALLTHRU */
-	default:
-		freemsg(mp);
-		return;
-	}
-}
--- a/usr/src/uts/common/inet/sctp/sctp_param.c	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * 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]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/stream.h>
-#include <sys/socket.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-
-#include <netinet/in.h>
-#include <netinet/ip6.h>
-
-#include <inet/common.h>
-#include <inet/ip.h>
-#include <inet/ip6.h>
-#include <inet/mi.h>
-#include <inet/mib2.h>
-#include <inet/nd.h>
-#include <inet/ipclassifier.h>
-#include "sctp_impl.h"
-#include "sctp_addr.h"
-
-#define	MS	1L
-#define	SECONDS	(1000 * MS)
-#define	MINUTES	(60 * SECONDS)
-#define	HOURS	(60 * MINUTES)
-#define	DAYS	(24 * HOURS)
-
-#define	PARAM_MAX (~(uint32_t)0)
-
-/* Max size IP datagram is 64k - 1 */
-#define	SCTP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + \
-					sizeof (sctp_hdr_t)))
-#define	SCTP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + \
-					sizeof (sctp_hdr_t)))
-/* Max of the above */
-#define	SCTP_MSS_MAX	SCTP_MSS_MAX_IPV4
-
-/* Largest SCTP port number */
-#define	SCTP_MAX_PORT	(64 * 1024 - 1)
-
-/*
- * Extra privileged ports. In host byte order.
- * Protected by sctp_epriv_port_lock.
- */
-#define	SCTP_NUM_EPRIV_PORTS	64
-
-/*
- * sctp_wroff_xtra is the extra space in front of SCTP/IP header for link
- * layer header.  It has to be a multiple of 4.
- */
-sctpparam_t lcl_sctp_wroff_xtra_param = { 0, 256, 32, "sctp_wroff_xtra" };
-
-/*
- * All of these are alterable, within the min/max values given, at run time.
- * Note that the default value of "sctp_time_wait_interval" is four minutes,
- * per the SCTP spec.
- */
-/* BEGIN CSTYLED */
-sctpparam_t	lcl_sctp_param_arr[] = {
- /*min		max		value		name */
- { 0,		128,		8,		"sctp_max_init_retr"},
- { 1,		128,		10,		"sctp_pa_max_retr"},
- { 1,		128,		5,		"sctp_pp_max_retr" },
- { 128,		(1<<30),	1024*1024,	"sctp_cwnd_max" },
- { 0,		10,		0,		"sctp_debug" },
- { 1024,	(32*1024),	1024,		"sctp_smallest_nonpriv_port"},
- { 1,		255,		64,		"sctp_ipv4_ttl"},
- { 0,		1*DAYS,		30*SECONDS,	"sctp_heartbeat_interval"},
- { 68,		65535,		1500,		"sctp_initial_mtu" },
- { 0,		1*DAYS,		10*MINUTES,	"sctp_mtu_probe_interval"},
- { 0,		1*DAYS,		2*MINUTES,	"sctp_new_secret_interval"},
- { 10*MS,	1*MINUTES,	100*MS,		"sctp_deferred_ack_interval" },
- { 0,		16,		0,		"sctp_snd_lowat_fraction" },
- { 0,		1,		0,		"sctp_ignore_path_mtu" },
- { 1024,	PARAM_MAX,     SCTP_RECV_HIWATER,"sctp_initial_ssthresh" },
- { 1024,	SCTP_MAX_PORT,	32*1024,	"sctp_smallest_anon_port"},
- { 1024,	SCTP_MAX_PORT,	SCTP_MAX_PORT,	"sctp_largest_anon_port"},
- { SCTP_XMIT_LOWATER, (1<<30), SCTP_XMIT_HIWATER,"sctp_xmit_hiwat"},
- { SCTP_XMIT_LOWATER, (1<<30), SCTP_XMIT_LOWATER,"sctp_xmit_lowat"},
- { SCTP_RECV_LOWATER, (1<<30), SCTP_RECV_HIWATER,"sctp_recv_hiwat"},
- { 8192,	(1<<30),	1024*1024,	"sctp_max_buf"},
- { 0,		65536,		20,		"sctp_rtt_updates"},
- { 0,		IPV6_MAX_HOPS,	IPV6_DEFAULT_HOPS,	"sctp_ipv6_hoplimit"},
- { 500*MS,	60*SECONDS,	1*SECONDS,	"sctp_rto_min"},
- { 1*SECONDS,	60000*SECONDS,	60*SECONDS,	"sctp_rto_max"},
- { 1*SECONDS,	60000*SECONDS,	3*SECONDS,	"sctp_rto_initial"},
- { 10*MS,	60000*SECONDS,	60*SECONDS,	"sctp_cookie_life"},
- { 1,		UINT16_MAX,	32,		"sctp_max_in_streams"},
- { 1,		UINT16_MAX,	32,		"sctp_initial_out_streams"},
- { 0,		300*SECONDS,	60*SECONDS,	"sctp_shutack_wait_bound" },
- { 2,		8,		4,		"sctp_maxburst" },
- { 0,		1,		0,		"sctp_addip_enabled" },
- { 1,		65536,		4,		"sctp_recv_hiwat_minmss" },
- { 1,		16,		4,		"sctp_slow_start_initial"},
- { 1,		16384,		4,		"sctp_slow_start_after_idle"},
- { 0,		1,		1,		"sctp_prsctp_enabled"},
- { 1,		10000,		3,		"sctp_fast_rxt_thresh"},
- { 1,		16,		2,		"sctp_deferred_acks_max"},
-};
-/* END CSTYLED */
-
-/* Get callback routine passed to nd_load by sctp_param_register */
-/* ARGSUSED */
-static int
-sctp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	sctpparam_t	*sctppa = (sctpparam_t *)cp;
-
-	(void) mi_mpprintf(mp, "%u", sctppa->sctp_param_val);
-	return (0);
-}
-
-/* Set callback routine passed to nd_load by sctp_param_register */
-/* ARGSUSED */
-static int
-sctp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
-{
-	long		new_value;
-	sctpparam_t	*sctppa = (sctpparam_t *)cp;
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < sctppa->sctp_param_min ||
-	    new_value > sctppa->sctp_param_max) {
-		return (EINVAL);
-	}
-	sctppa->sctp_param_val = new_value;
-	return (0);
-}
-
-/* ndd set routine for sctp_wroff_xtra. */
-/* ARGSUSED */
-static int
-sctp_wroff_xtra_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long		new_value;
-	sctpparam_t	*sctppa = (sctpparam_t *)cp;
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < sctppa->sctp_param_min ||
-	    new_value > sctppa->sctp_param_max) {
-		return (EINVAL);
-	}
-	/*
-	 * Need to make sure new_value is a multiple of 8.  If it is not,
-	 * round it up.
-	 */
-	if (new_value & 0x7) {
-		new_value = (new_value & ~0x7) + 0x8;
-	}
-	sctppa->sctp_param_val = new_value;
-	return (0);
-}
-
-/*
- * Note: No locks are held when inspecting sctp_g_*epriv_ports
- * but instead the code relies on:
- * - the fact that the address of the array and its size never changes
- * - the atomic assignment of the elements of the array
- */
-/* ARGSUSED */
-static int
-sctp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	int i;
-	sctp_stack_t	*sctps = Q_TO_CONN(q)->conn_netstack->netstack_sctp;
-
-	for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
-		if (sctps->sctps_g_epriv_ports[i] != 0)
-			(void) mi_mpprintf(mp, "%d ",
-			    sctps->sctps_g_epriv_ports[i]);
-	}
-	return (0);
-}
-
-/*
- * Hold a lock while changing sctp_g_epriv_ports to prevent multiple
- * threads from changing it at the same time.
- */
-/* ARGSUSED */
-static int
-sctp_extra_priv_ports_add(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	sctp_stack_t	*sctps = Q_TO_CONN(q)->conn_netstack->netstack_sctp;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value <= 0 || new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	mutex_enter(&sctps->sctps_epriv_port_lock);
-	/* Check if the value is already in the list */
-	for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
-		if (new_value == sctps->sctps_g_epriv_ports[i]) {
-			mutex_exit(&sctps->sctps_epriv_port_lock);
-			return (EEXIST);
-		}
-	}
-	/* Find an empty slot */
-	for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
-		if (sctps->sctps_g_epriv_ports[i] == 0)
-			break;
-	}
-	if (i == sctps->sctps_g_num_epriv_ports) {
-		mutex_exit(&sctps->sctps_epriv_port_lock);
-		return (EOVERFLOW);
-	}
-	/* Set the new value */
-	sctps->sctps_g_epriv_ports[i] = (uint16_t)new_value;
-	mutex_exit(&sctps->sctps_epriv_port_lock);
-	return (0);
-}
-
-/*
- * Hold a lock while changing sctp_g_epriv_ports to prevent multiple
- * threads from changing it at the same time.
- */
-/* ARGSUSED */
-static int
-sctp_extra_priv_ports_del(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	sctp_stack_t	*sctps = Q_TO_CONN(q)->conn_netstack->netstack_sctp;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value <= 0 || new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	mutex_enter(&sctps->sctps_epriv_port_lock);
-	/* Check that the value is already in the list */
-	for (i = 0; i < sctps->sctps_g_num_epriv_ports; i++) {
-		if (sctps->sctps_g_epriv_ports[i] == new_value)
-			break;
-	}
-	if (i == sctps->sctps_g_num_epriv_ports) {
-		mutex_exit(&sctps->sctps_epriv_port_lock);
-		return (ESRCH);
-	}
-	/* Clear the value */
-	sctps->sctps_g_epriv_ports[i] = 0;
-	mutex_exit(&sctps->sctps_epriv_port_lock);
-	return (0);
-}
-
-/*
- * Walk through the param array specified registering each element with the
- * named dispatch handler.
- */
-boolean_t
-sctp_param_register(IDP *ndp, sctpparam_t *sctppa, int cnt, sctp_stack_t *sctps)
-{
-
-	if (*ndp != NULL) {
-		return (B_TRUE);
-	}
-
-	for (; cnt-- > 0; sctppa++) {
-		if (sctppa->sctp_param_name && sctppa->sctp_param_name[0]) {
-			if (!nd_load(ndp, sctppa->sctp_param_name,
-			    sctp_param_get, sctp_param_set,
-			    (caddr_t)sctppa)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-	sctps->sctps_wroff_xtra_param = kmem_zalloc(sizeof (sctpparam_t),
-	    KM_SLEEP);
-	bcopy(&lcl_sctp_wroff_xtra_param, sctps->sctps_wroff_xtra_param,
-	    sizeof (sctpparam_t));
-	if (!nd_load(ndp, sctps->sctps_wroff_xtra_param->sctp_param_name,
-	    sctp_param_get, sctp_wroff_xtra_set,
-	    (caddr_t)sctps->sctps_wroff_xtra_param)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "sctp_extra_priv_ports",
-	    sctp_extra_priv_ports_get, NULL, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "sctp_extra_priv_ports_add",
-	    NULL, sctp_extra_priv_ports_add, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "sctp_extra_priv_ports_del",
-	    NULL, sctp_extra_priv_ports_del, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	return (B_TRUE);
-}
-
-boolean_t
-sctp_nd_init(sctp_stack_t *sctps)
-{
-	sctpparam_t *pa;
-
-	pa = kmem_alloc(sizeof (lcl_sctp_param_arr), KM_SLEEP);
-	bcopy(lcl_sctp_param_arr, pa, sizeof (lcl_sctp_param_arr));
-	sctps->sctps_params = pa;
-	return (sctp_param_register(&sctps->sctps_g_nd, pa,
-	    A_CNT(lcl_sctp_param_arr), sctps));
-}
-
-int
-sctp_nd_getset(queue_t *q, MBLKP mp)
-{
-	sctp_stack_t	*sctps = Q_TO_CONN(q)->conn_netstack->netstack_sctp;
-
-	return (nd_getset(q, sctps->sctps_g_nd, mp));
-}
-
-void
-sctp_nd_free(sctp_stack_t *sctps)
-{
-	nd_free(&sctps->sctps_g_nd);
-	kmem_free(sctps->sctps_params, sizeof (lcl_sctp_param_arr));
-	sctps->sctps_params = NULL;
-	kmem_free(sctps->sctps_wroff_xtra_param, sizeof (sctpparam_t));
-	sctps->sctps_wroff_xtra_param = NULL;
-
-}
--- a/usr/src/uts/common/inet/sctp/sctp_stack.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/sctp/sctp_stack.h	Fri Mar 26 17:53:11 2010 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -80,7 +80,7 @@
 
 #define	SCTP_NUM_EPRIV_PORTS	64
 	int		sctps_g_num_epriv_ports;
-	uint16_t	sctps_g_epriv_ports[SCTP_NUM_EPRIV_PORTS];
+	in_port_t	sctps_g_epriv_ports[SCTP_NUM_EPRIV_PORTS];
 	kmutex_t	sctps_epriv_port_lock;
 	uint_t		sctps_next_port_to_try;
 
@@ -91,10 +91,8 @@
 	struct sctp_tf_s	*sctps_conn_fanout;
 	uint_t			sctps_conn_hash_size;
 
-	/* Only modified during _init and _fini thus no locking is needed. */
-	caddr_t			sctps_g_nd;
-	struct sctpparam_s	*sctps_params;
-	struct sctpparam_s	*sctps_wroff_xtra_param;
+	/* holds sctp tunables */
+	struct mod_prop_info_s	*sctps_propinfo_tbl;
 
 /* This lock protects the SCTP recvq_tq_list array and recvq_tq_list_cur_sz. */
 	kmutex_t		sctps_rq_tq_lock;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/sctp/sctp_tunables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,218 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/sctp/sctp_stack.h>
+#include <inet/sctp/sctp_impl.h>
+#include <sys/sunddi.h>
+
+/* Max size IP datagram is 64k - 1 */
+#define	SCTP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + \
+					sizeof (sctp_hdr_t)))
+#define	SCTP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + \
+					sizeof (sctp_hdr_t)))
+/* Max of the above */
+#define	SCTP_MSS_MAX	SCTP_MSS_MAX_IPV4
+
+/*
+ * All of these are alterable, within the min/max values given, at run time.
+ *
+ * Note: All those tunables which do not start with "sctp_" are Committed and
+ * therefore are public. See PSARC 2009/306.
+ */
+mod_prop_info_t sctp_propinfo_tbl[] = {
+	{ "sctp_max_init_retr", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 128, 8}, {8} },
+
+	{ "sctp_pa_max_retr", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 128, 10}, {10} },
+
+	{ "sctp_pp_max_retr", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 128, 5}, {5} },
+
+	{ "sctp_cwnd_max", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {128, (1<<30), 1024*1024}, {1024*1024} },
+
+	{ "smallest_nonpriv_port", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, (32*1024), 1024}, {1024} },
+
+	{ "sctp_ipv4_ttl", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, 64}, {64} },
+
+	{ "sctp_heartbeat_interval", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1*DAYS, 30*SECONDS}, {30*SECONDS} },
+
+	{ "sctp_initial_mtu", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {68, 65535, 1500}, {1500} },
+
+	{ "sctp_mtu_probe_interval", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1*DAYS, 10*MINUTES}, {10*MINUTES} },
+
+	{ "sctp_new_secret_interval", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 1*DAYS, 2*MINUTES}, {2*MINUTES} },
+
+	/* tunable - 10 */
+	{ "sctp_deferred_ack_interval", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10*MS, 1*MINUTES, 100*MS}, {100*MS} },
+
+	{ "sctp_snd_lowat_fraction", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 16, 0}, {0} },
+
+	{ "sctp_ignore_path_mtu", MOD_PROTO_SCTP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "sctp_initial_ssthresh", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, UINT32_MAX, SCTP_RECV_HIWATER}, { SCTP_RECV_HIWATER} },
+
+	{ "smallest_anon_port", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, 32*1024}, {32*1024} },
+
+	{ "largest_anon_port", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, ULP_MAX_PORT}, {ULP_MAX_PORT} },
+
+	{ "send_maxbuf", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {SCTP_XMIT_LOWATER,  (1<<30),  SCTP_XMIT_HIWATER},
+	    {SCTP_XMIT_HIWATER} },
+
+	{ "sctp_xmit_lowat", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {SCTP_XMIT_LOWATER,  (1<<30),  SCTP_XMIT_LOWATER},
+	    {SCTP_XMIT_LOWATER} },
+
+	{ "recv_maxbuf", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {SCTP_RECV_LOWATER,  (1<<30),  SCTP_RECV_HIWATER},
+	    {SCTP_RECV_HIWATER} },
+
+	{ "sctp_max_buf", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {8192, (1<<30), 1024*1024}, {1024*1024} },
+
+	/* tunable - 20 */
+	{ "sctp_rtt_updates", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 65536, 20}, {20} },
+
+	{ "sctp_ipv6_hoplimit", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS}, {IPV6_DEFAULT_HOPS} },
+
+	{ "sctp_rto_min", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {500*MS, 60*SECONDS, 1*SECONDS}, {1*SECONDS} },
+
+	{ "sctp_rto_max", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, 60000*SECONDS, 60*SECONDS}, {60*SECONDS} },
+
+	{ "sctp_rto_initial", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, 60000*SECONDS, 3*SECONDS}, {3*SECONDS} },
+
+	{ "sctp_cookie_life", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10*MS, 60000*SECONDS, 60*SECONDS}, {60*SECONDS} },
+
+	{ "sctp_max_in_streams", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, UINT16_MAX, 32}, {32} },
+
+	{ "sctp_initial_out_streams", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, UINT16_MAX, 32}, {32} },
+
+	{ "sctp_shutack_wait_bound", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 300*SECONDS, 60*SECONDS}, {60*SECONDS} },
+
+	{ "sctp_maxburst", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {2, 8, 4}, {4} },
+
+	/* tunable - 30 */
+	{ "sctp_addip_enabled", MOD_PROTO_SCTP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "sctp_recv_hiwat_minmss", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 65536, 4}, {4} },
+
+	{ "sctp_slow_start_initial", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 16, 4}, {4} },
+
+	{ "sctp_slow_start_after_idle", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 16384, 4}, {4} },
+
+	{ "sctp_prsctp_enabled", MOD_PROTO_SCTP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "sctp_fast_rxt_thresh", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 10000, 3}, {3} },
+
+	{ "sctp_deferred_acks_max", MOD_PROTO_SCTP,
+	    mod_set_uint32, mod_get_uint32,
+	    { 1, 16, 2}, {2} },
+
+	/*
+	 * sctp_wroff_xtra is the extra space in front of SCTP/IP header
+	 * for link layer header.  It has to be a multiple of 8.
+	 */
+	{ "sctp_wroff_xtra", MOD_PROTO_SCTP,
+	    mod_set_aligned, mod_get_uint32,
+	    {0, 256, 32}, {32} },
+
+	{ "extra_priv_ports", MOD_PROTO_SCTP,
+	    mod_set_extra_privports, mod_get_extra_privports,
+	    {1, ULP_MAX_PORT, 0}, {0} },
+
+	{ "?", MOD_PROTO_SCTP, NULL, mod_get_allprop, {0}, {0} },
+
+	{ NULL, 0, NULL, NULL, {0}, {0} }
+};
+
+int sctp_propinfo_count = A_CNT(sctp_propinfo_tbl);
--- a/usr/src/uts/common/inet/sctp/sctpddi.c	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * 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]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <sys/types.h>
-#include <sys/conf.h>
-#include <sys/modctl.h>
-#include <inet/common.h>
-#include <inet/ip.h>
-
-#define	INET_NAME	"sctp"
-#define	INET_DEVDESC	"SCTP device"
-#define	INET_DEVSTRTAB	sctpinfo
-#define	INET_DEVMINOR	0
-#define	INET_DEVMTFLAGS	D_MP
-
-#include "../inetddi.c"
-
-int
-_init(void)
-{
-	/*
-	 * device initialization happens when the actual code containing
-	 * module (/kernel/drv/ip) is loaded, and driven from ip_ddi_init()
-	 */
-	return (mod_install(&modlinkage));
-}
-
-int
-_fini(void)
-{
-	return (mod_remove(&modlinkage));
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
--- a/usr/src/uts/common/inet/sctp_ip.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/sctp_ip.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -45,7 +45,6 @@
     ip_recv_attr_t *, mblk_t *, sctp_stack_t *);
 
 extern void sctp_input(conn_t *, ipha_t *, ip6_t *, mblk_t *, ip_recv_attr_t *);
-extern void sctp_wput(queue_t *, mblk_t *);
 extern void sctp_ootb_input(mblk_t *, ip_recv_attr_t *, ip_stack_t *);
 extern void sctp_hash_init(sctp_stack_t *);
 extern void sctp_hash_destroy(sctp_stack_t *);
--- a/usr/src/uts/common/inet/tcp/tcp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -77,7 +77,6 @@
 #include <inet/ip_ndp.h>
 #include <inet/proto_set.h>
 #include <inet/mib2.h>
-#include <inet/nd.h>
 #include <inet/optcom.h>
 #include <inet/snmpcom.h>
 #include <inet/kstatcom.h>
@@ -285,23 +284,7 @@
 static int	tcp_connect_ipv6(tcp_t *tcp, in6_addr_t *dstaddrp,
 		    in_port_t dstport, uint32_t flowinfo,
 		    uint_t srcid, uint32_t scope_id);
-static int	tcp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp,
-		    cred_t *cr);
-static int	tcp_extra_priv_ports_add(queue_t *q, mblk_t *mp,
-		    char *value, caddr_t cp, cred_t *cr);
-static int	tcp_extra_priv_ports_del(queue_t *q, mblk_t *mp,
-		    char *value, caddr_t cp, cred_t *cr);
 static void	tcp_iss_init(tcp_t *tcp);
-static int	tcp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
-static boolean_t tcp_param_register(IDP *ndp, tcpparam_t *tcppa, int cnt,
-    tcp_stack_t *);
-static int	tcp_param_set(queue_t *q, mblk_t *mp, char *value,
-		    caddr_t cp, cred_t *cr);
-static int	tcp_param_set_aligned(queue_t *q, mblk_t *mp, char *value,
-		    caddr_t cp, cred_t *cr);
-static void	tcp_iss_key_init(uint8_t *phrase, int len, tcp_stack_t *);
-static int	tcp_1948_phrase_set(queue_t *q, mblk_t *mp, char *value,
-		    caddr_t cp, cred_t *cr);
 static void	tcp_reinit(tcp_t *tcp);
 static void	tcp_reinit_values(tcp_t *tcp);
 
@@ -415,98 +398,14 @@
 	(XPG4_1|EXPINLINE)	/* PROVIDER_flag */
 };
 
-#define	PARAM_MAX (~(uint32_t)0)
-
-/* Max size IP datagram is 64k - 1 */
-#define	TCP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + sizeof (tcpha_t)))
-#define	TCP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + sizeof (tcpha_t)))
-/* Max of the above */
-#define	TCP_MSS_MAX	TCP_MSS_MAX_IPV4
-
-/* Largest TCP port number */
-#define	TCP_MAX_PORT	(64 * 1024 - 1)
-
 /*
- * tcp_wroff_xtra is the extra space in front of TCP/IP header for link
- * layer header.  It has to be a multiple of 4.
+ * TCP tunables related declarations. Definitions are in tcp_tunables.c
  */
-static tcpparam_t lcl_tcp_wroff_xtra_param = { 0, 256, 32, "tcp_wroff_xtra" };
+extern mod_prop_info_t tcp_propinfo_tbl[];
+extern int tcp_propinfo_count;
 
 #define	MB	(1024 * 1024)
 
-/*
- * All of these are alterable, within the min/max values given, at run time.
- * Note that the default value of "tcp_time_wait_interval" is four minutes,
- * per the TCP spec.
- */
-/* BEGIN CSTYLED */
-static tcpparam_t	lcl_tcp_param_arr[] = {
- /*min		max		value		name */
- { 1*SECONDS,	10*MINUTES,	1*MINUTES,	"tcp_time_wait_interval"},
- { 1,		PARAM_MAX,	128,		"tcp_conn_req_max_q" },
- { 0,		PARAM_MAX,	1024,		"tcp_conn_req_max_q0" },
- { 1,		1024,		1,		"tcp_conn_req_min" },
- { 0*MS,	20*SECONDS,	0*MS,		"tcp_conn_grace_period" },
- { 128,		(1<<30),	1*MB,		"tcp_cwnd_max" },
- { 0,		10,		0,		"tcp_debug" },
- { 1024,	(32*1024),	1024,		"tcp_smallest_nonpriv_port"},
- { 1*SECONDS,	PARAM_MAX,	3*MINUTES,	"tcp_ip_abort_cinterval"},
- { 1*SECONDS,	PARAM_MAX,	3*MINUTES,	"tcp_ip_abort_linterval"},
- { 500*MS,	PARAM_MAX,	5*MINUTES,	"tcp_ip_abort_interval"},
- { 1*SECONDS,	PARAM_MAX,	10*SECONDS,	"tcp_ip_notify_cinterval"},
- { 500*MS,	PARAM_MAX,	10*SECONDS,	"tcp_ip_notify_interval"},
- { 1,		255,		64,		"tcp_ipv4_ttl"},
- { 10*SECONDS,	10*DAYS,	2*HOURS,	"tcp_keepalive_interval"},
- { 0,		100,		10,		"tcp_maxpsz_multiplier" },
- { 1,		TCP_MSS_MAX_IPV4, 536,		"tcp_mss_def_ipv4"},
- { 1,		TCP_MSS_MAX_IPV4, TCP_MSS_MAX_IPV4, "tcp_mss_max_ipv4"},
- { 1,		TCP_MSS_MAX,	108,		"tcp_mss_min"},
- { 1,		(64*1024)-1,	(4*1024)-1,	"tcp_naglim_def"},
- { 1*MS,	20*SECONDS,	1*SECONDS,	"tcp_rexmit_interval_initial"},
- { 1*MS,	2*HOURS,	60*SECONDS,	"tcp_rexmit_interval_max"},
- { 1*MS,	2*HOURS,	400*MS,		"tcp_rexmit_interval_min"},
- { 1*MS,	1*MINUTES,	100*MS,		"tcp_deferred_ack_interval" },
- { 0,		16,		0,		"tcp_snd_lowat_fraction" },
- { 1,		10000,		3,		"tcp_dupack_fast_retransmit" },
- { 0,		1,		0,		"tcp_ignore_path_mtu" },
- { 1024,	TCP_MAX_PORT,	32*1024,	"tcp_smallest_anon_port"},
- { 1024,	TCP_MAX_PORT,	TCP_MAX_PORT,	"tcp_largest_anon_port"},
- { TCP_XMIT_LOWATER, (1<<30), TCP_XMIT_HIWATER,"tcp_xmit_hiwat"},
- { TCP_XMIT_LOWATER, (1<<30), TCP_XMIT_LOWATER,"tcp_xmit_lowat"},
- { TCP_RECV_LOWATER, (1<<30), TCP_RECV_HIWATER,"tcp_recv_hiwat"},
- { 1,		65536,		4,		"tcp_recv_hiwat_minmss"},
- { 1*SECONDS,	PARAM_MAX,	675*SECONDS,	"tcp_fin_wait_2_flush_interval"},
- { 8192,	(1<<30),	1*MB,		"tcp_max_buf"},
-/*
- * Question:  What default value should I set for tcp_strong_iss?
- */
- { 0,		2,		1,		"tcp_strong_iss"},
- { 0,		65536,		20,		"tcp_rtt_updates"},
- { 0,		1,		1,		"tcp_wscale_always"},
- { 0,		1,		0,		"tcp_tstamp_always"},
- { 0,		1,		1,		"tcp_tstamp_if_wscale"},
- { 0*MS,	2*HOURS,	0*MS,		"tcp_rexmit_interval_extra"},
- { 0,		16,		2,		"tcp_deferred_acks_max"},
- { 1,		16384,		4,		"tcp_slow_start_after_idle"},
- { 1,		4,		4,		"tcp_slow_start_initial"},
- { 0,		2,		2,		"tcp_sack_permitted"},
- { 0,		IPV6_MAX_HOPS,	IPV6_DEFAULT_HOPS,	"tcp_ipv6_hoplimit"},
- { 1,		TCP_MSS_MAX_IPV6, 1220,		"tcp_mss_def_ipv6"},
- { 1,		TCP_MSS_MAX_IPV6, TCP_MSS_MAX_IPV6, "tcp_mss_max_ipv6"},
- { 0,		1,		0,		"tcp_rev_src_routes"},
- { 10*MS,	500*MS,		50*MS,		"tcp_local_dack_interval"},
- { 0,		16,		8,		"tcp_local_dacks_max"},
- { 0,		2,		1,		"tcp_ecn_permitted"},
- { 0,		1,		1,		"tcp_rst_sent_rate_enabled"},
- { 0,		PARAM_MAX,	40,		"tcp_rst_sent_rate"},
- { 0,		100*MS,		50*MS,		"tcp_push_timer_interval"},
- { 0,		1,		0,		"tcp_use_smss_as_mss_opt"},
- { 0,		PARAM_MAX,	8*MINUTES,	"tcp_keepalive_abort_interval"},
- { 0,		1,		0,		"tcp_dev_flow_ctl"},
- { 0,		PARAM_MAX,	100*SECONDS,	"tcp_reass_timeout"}
-};
-/* END CSTYLED */
-
 #define	IS_VMLOANED_MBLK(mp) \
 	(((mp)->b_datap->db_struioflag & STRUIO_ZC) != 0)
 
@@ -1957,110 +1856,6 @@
 }
 
 /*
- * Note: No locks are held when inspecting tcp_g_*epriv_ports
- * but instead the code relies on:
- * - the fact that the address of the array and its size never changes
- * - the atomic assignment of the elements of the array
- */
-/* ARGSUSED */
-static int
-tcp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	int i;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	for (i = 0; i < tcps->tcps_g_num_epriv_ports; i++) {
-		if (tcps->tcps_g_epriv_ports[i] != 0)
-			(void) mi_mpprintf(mp, "%d ",
-			    tcps->tcps_g_epriv_ports[i]);
-	}
-	return (0);
-}
-
-/*
- * Hold a lock while changing tcp_g_epriv_ports to prevent multiple
- * threads from changing it at the same time.
- */
-/* ARGSUSED */
-static int
-tcp_extra_priv_ports_add(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value <= 0 || new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	mutex_enter(&tcps->tcps_epriv_port_lock);
-	/* Check if the value is already in the list */
-	for (i = 0; i < tcps->tcps_g_num_epriv_ports; i++) {
-		if (new_value == tcps->tcps_g_epriv_ports[i]) {
-			mutex_exit(&tcps->tcps_epriv_port_lock);
-			return (EEXIST);
-		}
-	}
-	/* Find an empty slot */
-	for (i = 0; i < tcps->tcps_g_num_epriv_ports; i++) {
-		if (tcps->tcps_g_epriv_ports[i] == 0)
-			break;
-	}
-	if (i == tcps->tcps_g_num_epriv_ports) {
-		mutex_exit(&tcps->tcps_epriv_port_lock);
-		return (EOVERFLOW);
-	}
-	/* Set the new value */
-	tcps->tcps_g_epriv_ports[i] = (uint16_t)new_value;
-	mutex_exit(&tcps->tcps_epriv_port_lock);
-	return (0);
-}
-
-/*
- * Hold a lock while changing tcp_g_epriv_ports to prevent multiple
- * threads from changing it at the same time.
- */
-/* ARGSUSED */
-static int
-tcp_extra_priv_ports_del(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 || new_value <= 0 ||
-	    new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	mutex_enter(&tcps->tcps_epriv_port_lock);
-	/* Check that the value is already in the list */
-	for (i = 0; i < tcps->tcps_g_num_epriv_ports; i++) {
-		if (tcps->tcps_g_epriv_ports[i] == new_value)
-			break;
-	}
-	if (i == tcps->tcps_g_num_epriv_ports) {
-		mutex_exit(&tcps->tcps_epriv_port_lock);
-		return (ESRCH);
-	}
-	/* Clear the value */
-	tcps->tcps_g_epriv_ports[i] = 0;
-	mutex_exit(&tcps->tcps_epriv_port_lock);
-	return (0);
-}
-
-/*
  * Handle reinitialization of a tcp structure.
  * Maintain "binding state" resetting the state to BOUND, LISTEN, or IDLE.
  */
@@ -3068,139 +2863,6 @@
 	return (0);
 }
 
-/* Get callback routine passed to nd_load by tcp_param_register */
-/* ARGSUSED */
-static int
-tcp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	tcpparam_t	*tcppa = (tcpparam_t *)cp;
-
-	(void) mi_mpprintf(mp, "%u", tcppa->tcp_param_val);
-	return (0);
-}
-
-/*
- * Walk through the param array specified registering each element with the
- * named dispatch handler.
- */
-static boolean_t
-tcp_param_register(IDP *ndp, tcpparam_t *tcppa, int cnt, tcp_stack_t *tcps)
-{
-	for (; cnt-- > 0; tcppa++) {
-		if (tcppa->tcp_param_name && tcppa->tcp_param_name[0]) {
-			if (!nd_load(ndp, tcppa->tcp_param_name,
-			    tcp_param_get, tcp_param_set,
-			    (caddr_t)tcppa)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-	tcps->tcps_wroff_xtra_param = kmem_zalloc(sizeof (tcpparam_t),
-	    KM_SLEEP);
-	bcopy(&lcl_tcp_wroff_xtra_param, tcps->tcps_wroff_xtra_param,
-	    sizeof (tcpparam_t));
-	if (!nd_load(ndp, tcps->tcps_wroff_xtra_param->tcp_param_name,
-	    tcp_param_get, tcp_param_set_aligned,
-	    (caddr_t)tcps->tcps_wroff_xtra_param)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_extra_priv_ports",
-	    tcp_extra_priv_ports_get, NULL, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_extra_priv_ports_add",
-	    NULL, tcp_extra_priv_ports_add, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_extra_priv_ports_del",
-	    NULL, tcp_extra_priv_ports_del, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_1948_phrase", NULL,
-	    tcp_1948_phrase_set, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-
-
-	if (!nd_load(ndp, "tcp_listener_limit_conf",
-	    tcp_listener_conf_get, NULL, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_listener_limit_conf_add",
-	    NULL, tcp_listener_conf_add, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "tcp_listener_limit_conf_del",
-	    NULL, tcp_listener_conf_del, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-
-	/*
-	 * Dummy ndd variables - only to convey obsolescence information
-	 * through printing of their name (no get or set routines)
-	 * XXX Remove in future releases ?
-	 */
-	if (!nd_load(ndp,
-	    "tcp_close_wait_interval(obsoleted - "
-	    "use tcp_time_wait_interval)", NULL, NULL, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	return (B_TRUE);
-}
-
-/* ndd set routine for tcp_wroff_xtra. */
-/* ARGSUSED */
-static int
-tcp_param_set_aligned(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long new_value;
-	tcpparam_t *tcppa = (tcpparam_t *)cp;
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < tcppa->tcp_param_min ||
-	    new_value > tcppa->tcp_param_max) {
-		return (EINVAL);
-	}
-	/*
-	 * Need to make sure new_value is a multiple of 4.  If it is not,
-	 * round it up.  For future 64 bit requirement, we actually make it
-	 * a multiple of 8.
-	 */
-	if (new_value & 0x7) {
-		new_value = (new_value & ~0x7) + 0x8;
-	}
-	tcppa->tcp_param_val = new_value;
-	return (0);
-}
-
-/* Set callback routine passed to nd_load by tcp_param_register */
-/* ARGSUSED */
-static int
-tcp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
-{
-	long	new_value;
-	tcpparam_t	*tcppa = (tcpparam_t *)cp;
-
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < tcppa->tcp_param_min ||
-	    new_value > tcppa->tcp_param_max) {
-		return (EINVAL);
-	}
-	tcppa->tcp_param_val = new_value;
-	return (0);
-}
-
 /*
  * tcp_rwnd_set() is called to adjust the receive window to a desired value.
  * We do not allow the receive window to shrink.  After setting rwnd,
@@ -4292,7 +3954,7 @@
 
 #define	PASSWD_SIZE 16  /* MUST be multiple of 4 */
 
-static void
+void
 tcp_iss_key_init(uint8_t *phrase, int len, tcp_stack_t *tcps)
 {
 	struct {
@@ -4346,23 +4008,6 @@
 	mutex_exit(&tcps->tcps_iss_key_lock);
 }
 
-/*
- * Set the RFC 1948 pass phrase
- */
-/* ARGSUSED */
-static int
-tcp_1948_phrase_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	/*
-	 * Basically, value contains a new pass phrase.  Pass it along!
-	 */
-	tcp_iss_key_init((uint8_t *)value, strlen(value), tcps);
-	return (0);
-}
-
 /* ARGSUSED */
 static int
 tcp_sack_info_constructor(void *buf, void *cdrarg, int kmflags)
@@ -4419,10 +4064,10 @@
 tcp_stack_init(netstackid_t stackid, netstack_t *ns)
 {
 	tcp_stack_t	*tcps;
-	tcpparam_t	*pa;
 	int		i;
 	int		error = 0;
 	major_t		major;
+	size_t		arrsz;
 
 	tcps = (tcp_stack_t *)kmem_zalloc(sizeof (*tcps), KM_SLEEP);
 	tcps->tcps_netstack = ns;
@@ -4432,8 +4077,8 @@
 	mutex_init(&tcps->tcps_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
 
 	tcps->tcps_g_num_epriv_ports = TCP_NUM_EPRIV_PORTS;
-	tcps->tcps_g_epriv_ports[0] = 2049;
-	tcps->tcps_g_epriv_ports[1] = 4045;
+	tcps->tcps_g_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
+	tcps->tcps_g_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
 	tcps->tcps_min_anonpriv_port = 512;
 
 	tcps->tcps_bind_fanout = kmem_zalloc(sizeof (tf_t) *
@@ -4454,12 +4099,10 @@
 	/* TCP's IPsec code calls the packet dropper. */
 	ip_drop_register(&tcps->tcps_dropper, "TCP IPsec policy enforcement");
 
-	pa = (tcpparam_t *)kmem_alloc(sizeof (lcl_tcp_param_arr), KM_SLEEP);
-	tcps->tcps_params = pa;
-	bcopy(lcl_tcp_param_arr, tcps->tcps_params, sizeof (lcl_tcp_param_arr));
-
-	(void) tcp_param_register(&tcps->tcps_g_nd, tcps->tcps_params,
-	    A_CNT(lcl_tcp_param_arr), tcps);
+	arrsz = tcp_propinfo_count * sizeof (mod_prop_info_t);
+	tcps->tcps_propinfo_tbl = (mod_prop_info_t *)kmem_alloc(arrsz,
+	    KM_SLEEP);
+	bcopy(tcp_propinfo_tbl, tcps->tcps_propinfo_tbl, arrsz);
 
 	/*
 	 * Note: To really walk the device tree you need the devinfo
@@ -4577,11 +4220,9 @@
 		kmem_free(tcps->tcps_sc[i], sizeof (tcp_stats_cpu_t));
 	kmem_free(tcps->tcps_sc, max_ncpus * sizeof (tcp_stats_cpu_t *));
 
-	nd_free(&tcps->tcps_g_nd);
-	kmem_free(tcps->tcps_params, sizeof (lcl_tcp_param_arr));
-	tcps->tcps_params = NULL;
-	kmem_free(tcps->tcps_wroff_xtra_param, sizeof (tcpparam_t));
-	tcps->tcps_wroff_xtra_param = NULL;
+	kmem_free(tcps->tcps_propinfo_tbl,
+	    tcp_propinfo_count * sizeof (mod_prop_info_t));
+	tcps->tcps_propinfo_tbl = NULL;
 
 	for (i = 0; i < TCP_BIND_FANOUT_SIZE; i++) {
 		ASSERT(tcps->tcps_bind_fanout[i].tf_tcp == NULL);
--- a/usr/src/uts/common/inet/tcp/tcp_misc.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp_misc.c	Fri Mar 26 17:53:11 2010 -0400
@@ -632,102 +632,6 @@
 }
 
 /*
- * Ndd param helper routine to return the current list of listener limit
- * configuration.
- */
-/* ARGSUSED */
-int
-tcp_listener_conf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-	tcp_listener_t	*tl;
-
-	mutex_enter(&tcps->tcps_listener_conf_lock);
-	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
-	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
-		(void) mi_mpprintf(mp, "%d:%d ", tl->tl_port, tl->tl_ratio);
-	}
-	mutex_exit(&tcps->tcps_listener_conf_lock);
-	return (0);
-}
-
-/*
- * Ndd param helper routine to add a new listener limit configuration.
- */
-/* ARGSUSED */
-int
-tcp_listener_conf_add(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	tcp_listener_t	*new_tl;
-	tcp_listener_t	*tl;
-	long		lport;
-	long		ratio;
-	char		*colon;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	if (ddi_strtol(value, &colon, 10, &lport) != 0 || lport <= 0 ||
-	    lport > USHRT_MAX || *colon != ':') {
-		return (EINVAL);
-	}
-	if (ddi_strtol(colon + 1, NULL, 10, &ratio) != 0 || ratio <= 0)
-		return (EINVAL);
-
-	mutex_enter(&tcps->tcps_listener_conf_lock);
-	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
-	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
-		/* There is an existing entry, so update its ratio value. */
-		if (tl->tl_port == lport) {
-			tl->tl_ratio = ratio;
-			mutex_exit(&tcps->tcps_listener_conf_lock);
-			return (0);
-		}
-	}
-
-	if ((new_tl = kmem_alloc(sizeof (tcp_listener_t), KM_NOSLEEP)) ==
-	    NULL) {
-		mutex_exit(&tcps->tcps_listener_conf_lock);
-		return (ENOMEM);
-	}
-
-	new_tl->tl_port = lport;
-	new_tl->tl_ratio = ratio;
-	list_insert_tail(&tcps->tcps_listener_conf, new_tl);
-	mutex_exit(&tcps->tcps_listener_conf_lock);
-	return (0);
-}
-
-/*
- * Ndd param helper routine to remove a listener limit configuration.
- */
-/* ARGSUSED */
-int
-tcp_listener_conf_del(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	tcp_listener_t	*tl;
-	long		lport;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
-
-	if (ddi_strtol(value, NULL, 10, &lport) != 0 || lport <= 0 ||
-	    lport > USHRT_MAX) {
-		return (EINVAL);
-	}
-	mutex_enter(&tcps->tcps_listener_conf_lock);
-	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
-	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
-		if (tl->tl_port == lport) {
-			list_remove(&tcps->tcps_listener_conf, tl);
-			mutex_exit(&tcps->tcps_listener_conf_lock);
-			kmem_free(tl, sizeof (tcp_listener_t));
-			return (0);
-		}
-	}
-	mutex_exit(&tcps->tcps_listener_conf_lock);
-	return (ESRCH);
-}
-
-/*
  * To remove all listener limit configuration in a tcp_stack_t.
  */
 void
--- a/usr/src/uts/common/inet/tcp/tcp_output.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/tcp/tcp_output.c	Fri Mar 26 17:53:11 2010 -0400
@@ -90,7 +90,6 @@
 	uchar_t *rptr;
 	struct iocblk	*iocp;
 	size_t size;
-	tcp_stack_t	*tcps = Q_TO_TCP(q)->tcp_tcps;
 
 	ASSERT(connp->conn_ref >= 2);
 
@@ -182,17 +181,6 @@
 			mi_copyin(q, mp, NULL,
 			    SIZEOF_STRUCT(strbuf, iocp->ioc_flag));
 			return;
-		case ND_SET:
-			/* nd_getset does the necessary checks */
-		case ND_GET:
-			if (nd_getset(q, tcps->tcps_g_nd, mp)) {
-				qreply(q, mp);
-				return;
-			}
-			CONN_INC_IOCTLREF(connp);
-			ip_wput_nondata(q, mp);
-			CONN_DEC_IOCTLREF(connp);
-			return;
 
 		default:
 			output_proc = tcp_wput_ioctl;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/tcp/tcp_tunables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,480 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <inet/ip.h>
+#include <inet/tcp_impl.h>
+#include <sys/multidata.h>
+#include <sys/sunddi.h>
+
+/* Max size IP datagram is 64k - 1 */
+#define	TCP_MSS_MAX_IPV4 (IP_MAXPACKET - (sizeof (ipha_t) + sizeof (tcpha_t)))
+#define	TCP_MSS_MAX_IPV6 (IP_MAXPACKET - (sizeof (ip6_t) + sizeof (tcpha_t)))
+
+/* Max of the above */
+#define	TCP_MSS_MAX		TCP_MSS_MAX_IPV4
+
+#define	TCP_XMIT_LOWATER	4096
+#define	TCP_XMIT_HIWATER	49152
+#define	TCP_RECV_LOWATER	2048
+#define	TCP_RECV_HIWATER	128000
+
+/*
+ * Set the RFC 1948 pass phrase
+ */
+/* ARGSUSED */
+static int
+tcp_set_1948phrase(void *cbarg,  cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pr_val, uint_t flags)
+{
+	tcp_stack_t	*tcps = (tcp_stack_t *)cbarg;
+
+	if (flags & MOD_PROP_DEFAULT)
+		return (ENOTSUP);
+
+	/*
+	 * Basically, value contains a new pass phrase.  Pass it along!
+	 */
+	tcp_iss_key_init((uint8_t *)pr_val, strlen(pr_val), tcps);
+	return (0);
+}
+
+/*
+ * returns the current list of listener limit configuration.
+ */
+/* ARGSUSED */
+static int
+tcp_listener_conf_get(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *val, uint_t psize, uint_t flags)
+{
+	tcp_stack_t	*tcps = (tcp_stack_t *)cbarg;
+	tcp_listener_t	*tl;
+	char		*pval = val;
+	size_t		nbytes = 0, tbytes = 0;
+	uint_t		size;
+	int		err = 0;
+
+	bzero(pval, psize);
+	size = psize;
+
+	if (flags & (MOD_PROP_DEFAULT|MOD_PROP_PERM|MOD_PROP_POSSIBLE))
+		return (0);
+
+	mutex_enter(&tcps->tcps_listener_conf_lock);
+	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
+	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
+		if (psize == size)
+			nbytes = snprintf(pval, size, "%d:%d",  tl->tl_port,
+			    tl->tl_ratio);
+		else
+			nbytes = snprintf(pval, size, ",%d:%d",  tl->tl_port,
+			    tl->tl_ratio);
+		size -= nbytes;
+		pval += nbytes;
+		tbytes += nbytes;
+		if (tbytes >= psize) {
+			/* Buffer overflow, stop copying information */
+			err = ENOBUFS;
+			break;
+		}
+	}
+ret:
+	mutex_exit(&tcps->tcps_listener_conf_lock);
+	return (err);
+}
+
+/*
+ * add a new listener limit configuration.
+ */
+/* ARGSUSED */
+static int
+tcp_listener_conf_add(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	tcp_listener_t	*new_tl;
+	tcp_listener_t	*tl;
+	long		lport;
+	long		ratio;
+	char		*colon;
+	tcp_stack_t	*tcps = (tcp_stack_t *)cbarg;
+
+	if (flags & MOD_PROP_DEFAULT)
+		return (ENOTSUP);
+
+	if (ddi_strtol(pval, &colon, 10, &lport) != 0 || lport <= 0 ||
+	    lport > USHRT_MAX || *colon != ':') {
+		return (EINVAL);
+	}
+	if (ddi_strtol(colon + 1, NULL, 10, &ratio) != 0 || ratio <= 0)
+		return (EINVAL);
+
+	mutex_enter(&tcps->tcps_listener_conf_lock);
+	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
+	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
+		/* There is an existing entry, so update its ratio value. */
+		if (tl->tl_port == lport) {
+			tl->tl_ratio = ratio;
+			mutex_exit(&tcps->tcps_listener_conf_lock);
+			return (0);
+		}
+	}
+
+	if ((new_tl = kmem_alloc(sizeof (tcp_listener_t), KM_NOSLEEP)) ==
+	    NULL) {
+		mutex_exit(&tcps->tcps_listener_conf_lock);
+		return (ENOMEM);
+	}
+
+	new_tl->tl_port = lport;
+	new_tl->tl_ratio = ratio;
+	list_insert_tail(&tcps->tcps_listener_conf, new_tl);
+	mutex_exit(&tcps->tcps_listener_conf_lock);
+	return (0);
+}
+
+/*
+ * remove a listener limit configuration.
+ */
+/* ARGSUSED */
+static int
+tcp_listener_conf_del(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	tcp_listener_t	*tl;
+	long		lport;
+	tcp_stack_t	*tcps = (tcp_stack_t *)cbarg;
+
+	if (flags & MOD_PROP_DEFAULT)
+		return (ENOTSUP);
+
+	if (ddi_strtol(pval, NULL, 10, &lport) != 0 || lport <= 0 ||
+	    lport > USHRT_MAX) {
+		return (EINVAL);
+	}
+	mutex_enter(&tcps->tcps_listener_conf_lock);
+	for (tl = list_head(&tcps->tcps_listener_conf); tl != NULL;
+	    tl = list_next(&tcps->tcps_listener_conf, tl)) {
+		if (tl->tl_port == lport) {
+			list_remove(&tcps->tcps_listener_conf, tl);
+			mutex_exit(&tcps->tcps_listener_conf_lock);
+			kmem_free(tl, sizeof (tcp_listener_t));
+			return (0);
+		}
+	}
+	mutex_exit(&tcps->tcps_listener_conf_lock);
+	return (ESRCH);
+}
+
+/*
+ * All of these are alterable, within the min/max values given, at run time.
+ *
+ * Note: All those tunables which do not start with "tcp_" are Committed and
+ * therefore are public. See PSARC 2009/306.
+ */
+mod_prop_info_t tcp_propinfo_tbl[] = {
+	/* tunable - 0 */
+	{ "tcp_time_wait_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, 10*MINUTES, 1*MINUTES}, {1*MINUTES} },
+
+	{ "tcp_conn_req_max_q", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, UINT32_MAX, 128}, {128} },
+
+	{ "tcp_conn_req_max_q0", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, UINT32_MAX, 1024}, {1024} },
+
+	{ "tcp_conn_req_min", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 1024, 1}, {1} },
+
+	{ "tcp_conn_grace_period", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0*MS, 20*SECONDS, 0*MS}, {0*MS} },
+
+	{ "tcp_cwnd_max", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {128, (1<<30), 1024*1024}, {1024*1024} },
+
+	{ "tcp_debug", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 10, 0}, {0} },
+
+	{ "smallest_nonpriv_port", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, (32*1024), 1024}, {1024} },
+
+	{ "tcp_ip_abort_cinterval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, UINT32_MAX, 3*MINUTES}, {3*MINUTES} },
+
+	{ "tcp_ip_abort_linterval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, UINT32_MAX, 3*MINUTES}, {3*MINUTES} },
+
+	/* tunable - 10 */
+	{ "tcp_ip_abort_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {500*MS, UINT32_MAX, 5*MINUTES}, {5*MINUTES} },
+
+	{ "tcp_ip_notify_cinterval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, UINT32_MAX, 10*SECONDS},
+	    {10*SECONDS} },
+
+	{ "tcp_ip_notify_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {500*MS, UINT32_MAX, 10*SECONDS}, {10*SECONDS} },
+
+	{ "tcp_ipv4_ttl", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, 64}, {64} },
+
+	{ "tcp_keepalive_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10*SECONDS, 10*DAYS, 2*HOURS}, {2*HOURS} },
+
+	{ "tcp_maxpsz_multiplier", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 100, 10}, {10} },
+
+	{ "tcp_mss_def_ipv4", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, TCP_MSS_MAX_IPV4, 536}, {536} },
+
+	{ "tcp_mss_max_ipv4", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, TCP_MSS_MAX_IPV4, TCP_MSS_MAX_IPV4},
+	    {TCP_MSS_MAX_IPV4} },
+
+	{ "tcp_mss_min", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, TCP_MSS_MAX, 108}, {108} },
+
+	{ "tcp_naglim_def", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, (64*1024)-1, (4*1024)-1}, {(4*1024)-1} },
+
+	/* tunable - 20 */
+	{ "tcp_rexmit_interval_initial", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*MS, 20*SECONDS, 1*SECONDS}, {1*SECONDS} },
+
+	{ "tcp_rexmit_interval_max", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*MS, 2*HOURS, 60*SECONDS}, {60*SECONDS} },
+
+	{ "tcp_rexmit_interval_min", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*MS, 2*HOURS, 400*MS}, {400*MS} },
+
+	{ "tcp_deferred_ack_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*MS, 1*MINUTES, 100*MS}, {100*MS} },
+
+	{ "tcp_snd_lowat_fraction", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 16, 0}, {0} },
+
+	{ "tcp_dupack_fast_retransmit", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 10000, 3}, {3} },
+
+	{ "tcp_ignore_path_mtu", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "smallest_anon_port", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, 32*1024}, {32*1024} },
+
+	{ "largest_anon_port", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, ULP_MAX_PORT},
+	    {ULP_MAX_PORT} },
+
+	{ "send_maxbuf", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {TCP_XMIT_LOWATER, (1<<30), TCP_XMIT_HIWATER},
+	    {TCP_XMIT_HIWATER} },
+
+	/* tunable - 30 */
+	{ "tcp_xmit_lowat", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {TCP_XMIT_LOWATER, (1<<30), TCP_XMIT_LOWATER},
+	    {TCP_XMIT_LOWATER} },
+
+	{ "recv_maxbuf", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {TCP_RECV_LOWATER, (1<<30), TCP_RECV_HIWATER},
+	    {TCP_RECV_HIWATER} },
+
+	{ "tcp_recv_hiwat_minmss", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 65536, 4}, {4} },
+
+	{ "tcp_fin_wait_2_flush_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1*SECONDS, UINT32_MAX, 675*SECONDS},
+	    {675*SECONDS} },
+
+	{ "tcp_max_buf", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {8192, (1<<30), 1024*1024}, {1024*1024} },
+
+	/*
+	 * Question:  What default value should I set for tcp_strong_iss?
+	 */
+	{ "tcp_strong_iss", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 2, 1}, {1} },
+
+	{ "tcp_rtt_updates", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 65536, 20}, {20} },
+
+	{ "tcp_wscale_always", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "tcp_tstamp_always", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "tcp_tstamp_if_wscale", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	/* tunable - 40 */
+	{ "tcp_rexmit_interval_extra", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0*MS, 2*HOURS, 0*MS}, {0*MS} },
+
+	{ "tcp_deferred_acks_max", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 16, 2}, {2} },
+
+	{ "tcp_slow_start_after_idle", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 16384, 4}, {4} },
+
+	{ "tcp_slow_start_initial", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 4, 4}, {4} },
+
+	{ "sack", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 2, 2}, {2} },
+
+	{ "tcp_ipv6_hoplimit", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS},
+	    {IPV6_DEFAULT_HOPS} },
+
+	{ "tcp_mss_def_ipv6", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, TCP_MSS_MAX_IPV6, 1220}, {1220} },
+
+	{ "tcp_mss_max_ipv6", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, TCP_MSS_MAX_IPV6, TCP_MSS_MAX_IPV6},
+	    {TCP_MSS_MAX_IPV6} },
+
+	{ "tcp_rev_src_routes", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "tcp_local_dack_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {10*MS, 500*MS, 50*MS}, {50*MS} },
+
+	/* tunable - 50 */
+	{ "tcp_local_dacks_max", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 16, 8}, {8} },
+
+	{ "ecn", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 2, 1}, {1} },
+
+	{ "tcp_rst_sent_rate_enabled", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "tcp_rst_sent_rate", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, UINT32_MAX, 40}, {40} },
+
+	{ "tcp_push_timer_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 100*MS, 50*MS}, {50*MS} },
+
+	{ "tcp_use_smss_as_mss_opt", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "tcp_keepalive_abort_interval", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, UINT32_MAX, 8*MINUTES}, {8*MINUTES} },
+
+	/*
+	 * tcp_wroff_xtra is the extra space in front of TCP/IP header for link
+	 * layer header.  It has to be a multiple of 8.
+	 */
+	{ "tcp_wroff_xtra", MOD_PROTO_TCP,
+	    mod_set_aligned, mod_get_uint32,
+	    {0, 256, 32}, {32} },
+
+	{ "tcp_dev_flow_ctl", MOD_PROTO_TCP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "tcp_reass_timeout", MOD_PROTO_TCP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, UINT32_MAX, 100*SECONDS}, {100*SECONDS} },
+
+	/* tunable - 60 */
+	{ "extra_priv_ports", MOD_PROTO_TCP,
+	    mod_set_extra_privports, mod_get_extra_privports,
+	    {1, ULP_MAX_PORT, 0}, {0} },
+
+	{ "tcp_1948_phrase", MOD_PROTO_TCP,
+	    tcp_set_1948phrase, NULL, {0}, {0} },
+
+	{ "tcp_listener_limit_conf", MOD_PROTO_TCP,
+	    NULL, tcp_listener_conf_get, {0}, {0} },
+
+	{ "tcp_listener_limit_conf_add", MOD_PROTO_TCP,
+	    tcp_listener_conf_add, NULL, {0}, {0} },
+
+	{ "tcp_listener_limit_conf_del", MOD_PROTO_TCP,
+	    tcp_listener_conf_del, NULL, {0}, {0} },
+
+	{ "?", MOD_PROTO_TCP, NULL, mod_get_allprop, {0}, {0} },
+
+	{ NULL, 0, NULL, NULL, {0}, {0} }
+};
+
+int tcp_propinfo_count = A_CNT(tcp_propinfo_tbl);
--- a/usr/src/uts/common/inet/tcp_impl.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/tcp_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -43,6 +43,7 @@
 #include <sys/clock_impl.h>	/* For LBOLT_FASTPATH{,64} */
 #include <inet/optcom.h>
 #include <inet/tcp.h>
+#include <inet/tunables.h>
 
 #define	TCP_MOD_ID	5105
 
@@ -65,13 +66,6 @@
  */
 #define	TCP_OLD_URP_INTERPRETATION	1
 
-/* Handy time related macros. */
-#define	MS	1L
-#define	SECONDS	(1000 * MS)
-#define	MINUTES	(60 * SECONDS)
-#define	HOURS	(60 * MINUTES)
-#define	DAYS	(24 * HOURS)
-
 /* TCP option length */
 #define	TCPOPT_NOP_LEN		1
 #define	TCPOPT_MAXSEG_LEN	4
@@ -407,80 +401,73 @@
 #define	TCP_REASS_SET_END(mp, u)	((mp)->b_prev = \
 					(mblk_t *)(uintptr_t)(u))
 
-/* Named Dispatch Parameter Management Structure */
-typedef struct tcpparam_s {
-	uint32_t	tcp_param_min;
-	uint32_t	tcp_param_max;
-	uint32_t	tcp_param_val;
-	char		*tcp_param_name;
-} tcpparam_t;
-
-
-#define	tcps_time_wait_interval		tcps_params[0].tcp_param_val
-#define	tcps_conn_req_max_q		tcps_params[1].tcp_param_val
-#define	tcps_conn_req_max_q0		tcps_params[2].tcp_param_val
-#define	tcps_conn_req_min		tcps_params[3].tcp_param_val
-#define	tcps_conn_grace_period		tcps_params[4].tcp_param_val
-#define	tcps_cwnd_max_			tcps_params[5].tcp_param_val
-#define	tcps_dbg			tcps_params[6].tcp_param_val
-#define	tcps_smallest_nonpriv_port	tcps_params[7].tcp_param_val
-#define	tcps_ip_abort_cinterval		tcps_params[8].tcp_param_val
-#define	tcps_ip_abort_linterval		tcps_params[9].tcp_param_val
-#define	tcps_ip_abort_interval		tcps_params[10].tcp_param_val
-#define	tcps_ip_notify_cinterval	tcps_params[11].tcp_param_val
-#define	tcps_ip_notify_interval		tcps_params[12].tcp_param_val
-#define	tcps_ipv4_ttl			tcps_params[13].tcp_param_val
-#define	tcps_keepalive_interval_high	tcps_params[14].tcp_param_max
-#define	tcps_keepalive_interval		tcps_params[14].tcp_param_val
-#define	tcps_keepalive_interval_low	tcps_params[14].tcp_param_min
-#define	tcps_maxpsz_multiplier		tcps_params[15].tcp_param_val
-#define	tcps_mss_def_ipv4		tcps_params[16].tcp_param_val
-#define	tcps_mss_max_ipv4		tcps_params[17].tcp_param_val
-#define	tcps_mss_min			tcps_params[18].tcp_param_val
-#define	tcps_naglim_def			tcps_params[19].tcp_param_val
-#define	tcps_rexmit_interval_initial	tcps_params[20].tcp_param_val
-#define	tcps_rexmit_interval_max	tcps_params[21].tcp_param_val
-#define	tcps_rexmit_interval_min	tcps_params[22].tcp_param_val
-#define	tcps_deferred_ack_interval	tcps_params[23].tcp_param_val
-#define	tcps_snd_lowat_fraction		tcps_params[24].tcp_param_val
-#define	tcps_dupack_fast_retransmit	tcps_params[25].tcp_param_val
-#define	tcps_ignore_path_mtu		tcps_params[26].tcp_param_val
-#define	tcps_smallest_anon_port		tcps_params[27].tcp_param_val
-#define	tcps_largest_anon_port		tcps_params[28].tcp_param_val
-#define	tcps_xmit_hiwat			tcps_params[29].tcp_param_val
-#define	tcps_xmit_lowat			tcps_params[30].tcp_param_val
-#define	tcps_recv_hiwat			tcps_params[31].tcp_param_val
-#define	tcps_recv_hiwat_minmss		tcps_params[32].tcp_param_val
-#define	tcps_fin_wait_2_flush_interval	tcps_params[33].tcp_param_val
-#define	tcps_max_buf			tcps_params[34].tcp_param_val
-#define	tcps_strong_iss			tcps_params[35].tcp_param_val
-#define	tcps_rtt_updates		tcps_params[36].tcp_param_val
-#define	tcps_wscale_always		tcps_params[37].tcp_param_val
-#define	tcps_tstamp_always		tcps_params[38].tcp_param_val
-#define	tcps_tstamp_if_wscale		tcps_params[39].tcp_param_val
-#define	tcps_rexmit_interval_extra	tcps_params[40].tcp_param_val
-#define	tcps_deferred_acks_max		tcps_params[41].tcp_param_val
-#define	tcps_slow_start_after_idle	tcps_params[42].tcp_param_val
-#define	tcps_slow_start_initial		tcps_params[43].tcp_param_val
-#define	tcps_sack_permitted		tcps_params[44].tcp_param_val
-#define	tcps_ipv6_hoplimit		tcps_params[45].tcp_param_val
-#define	tcps_mss_def_ipv6		tcps_params[46].tcp_param_val
-#define	tcps_mss_max_ipv6		tcps_params[47].tcp_param_val
-#define	tcps_rev_src_routes		tcps_params[48].tcp_param_val
-#define	tcps_local_dack_interval	tcps_params[49].tcp_param_val
-#define	tcps_local_dacks_max		tcps_params[50].tcp_param_val
-#define	tcps_ecn_permitted		tcps_params[51].tcp_param_val
-#define	tcps_rst_sent_rate_enabled	tcps_params[52].tcp_param_val
-#define	tcps_rst_sent_rate		tcps_params[53].tcp_param_val
-#define	tcps_push_timer_interval	tcps_params[54].tcp_param_val
-#define	tcps_use_smss_as_mss_opt	tcps_params[55].tcp_param_val
-#define	tcps_keepalive_abort_interval_high	tcps_params[56].tcp_param_max
-#define	tcps_keepalive_abort_interval		tcps_params[56].tcp_param_val
-#define	tcps_keepalive_abort_interval_low	tcps_params[56].tcp_param_min
-#define	tcps_dev_flow_ctl		tcps_params[57].tcp_param_val
-#define	tcps_reass_timeout		tcps_params[58].tcp_param_val
-
-#define	tcps_wroff_xtra	tcps_wroff_xtra_param->tcp_param_val
+#define	tcps_time_wait_interval		tcps_propinfo_tbl[0].prop_cur_uval
+#define	tcps_conn_req_max_q		tcps_propinfo_tbl[1].prop_cur_uval
+#define	tcps_conn_req_max_q0		tcps_propinfo_tbl[2].prop_cur_uval
+#define	tcps_conn_req_min		tcps_propinfo_tbl[3].prop_cur_uval
+#define	tcps_conn_grace_period		tcps_propinfo_tbl[4].prop_cur_uval
+#define	tcps_cwnd_max_			tcps_propinfo_tbl[5].prop_cur_uval
+#define	tcps_dbg			tcps_propinfo_tbl[6].prop_cur_uval
+#define	tcps_smallest_nonpriv_port	tcps_propinfo_tbl[7].prop_cur_uval
+#define	tcps_ip_abort_cinterval		tcps_propinfo_tbl[8].prop_cur_uval
+#define	tcps_ip_abort_linterval		tcps_propinfo_tbl[9].prop_cur_uval
+#define	tcps_ip_abort_interval		tcps_propinfo_tbl[10].prop_cur_uval
+#define	tcps_ip_notify_cinterval	tcps_propinfo_tbl[11].prop_cur_uval
+#define	tcps_ip_notify_interval		tcps_propinfo_tbl[12].prop_cur_uval
+#define	tcps_ipv4_ttl			tcps_propinfo_tbl[13].prop_cur_uval
+#define	tcps_keepalive_interval_high	tcps_propinfo_tbl[14].prop_max_uval
+#define	tcps_keepalive_interval		tcps_propinfo_tbl[14].prop_cur_uval
+#define	tcps_keepalive_interval_low	tcps_propinfo_tbl[14].prop_min_uval
+#define	tcps_maxpsz_multiplier		tcps_propinfo_tbl[15].prop_cur_uval
+#define	tcps_mss_def_ipv4		tcps_propinfo_tbl[16].prop_cur_uval
+#define	tcps_mss_max_ipv4		tcps_propinfo_tbl[17].prop_cur_uval
+#define	tcps_mss_min			tcps_propinfo_tbl[18].prop_cur_uval
+#define	tcps_naglim_def			tcps_propinfo_tbl[19].prop_cur_uval
+#define	tcps_rexmit_interval_initial	tcps_propinfo_tbl[20].prop_cur_uval
+#define	tcps_rexmit_interval_max	tcps_propinfo_tbl[21].prop_cur_uval
+#define	tcps_rexmit_interval_min	tcps_propinfo_tbl[22].prop_cur_uval
+#define	tcps_deferred_ack_interval	tcps_propinfo_tbl[23].prop_cur_uval
+#define	tcps_snd_lowat_fraction		tcps_propinfo_tbl[24].prop_cur_uval
+#define	tcps_dupack_fast_retransmit	tcps_propinfo_tbl[25].prop_cur_uval
+#define	tcps_ignore_path_mtu		tcps_propinfo_tbl[26].prop_cur_bval
+#define	tcps_smallest_anon_port		tcps_propinfo_tbl[27].prop_cur_uval
+#define	tcps_largest_anon_port		tcps_propinfo_tbl[28].prop_cur_uval
+#define	tcps_xmit_hiwat			tcps_propinfo_tbl[29].prop_cur_uval
+#define	tcps_xmit_lowat			tcps_propinfo_tbl[30].prop_cur_uval
+#define	tcps_recv_hiwat			tcps_propinfo_tbl[31].prop_cur_uval
+#define	tcps_recv_hiwat_minmss		tcps_propinfo_tbl[32].prop_cur_uval
+#define	tcps_fin_wait_2_flush_interval	tcps_propinfo_tbl[33].prop_cur_uval
+#define	tcps_max_buf			tcps_propinfo_tbl[34].prop_cur_uval
+#define	tcps_strong_iss			tcps_propinfo_tbl[35].prop_cur_uval
+#define	tcps_rtt_updates		tcps_propinfo_tbl[36].prop_cur_uval
+#define	tcps_wscale_always		tcps_propinfo_tbl[37].prop_cur_bval
+#define	tcps_tstamp_always		tcps_propinfo_tbl[38].prop_cur_bval
+#define	tcps_tstamp_if_wscale		tcps_propinfo_tbl[39].prop_cur_bval
+#define	tcps_rexmit_interval_extra	tcps_propinfo_tbl[40].prop_cur_uval
+#define	tcps_deferred_acks_max		tcps_propinfo_tbl[41].prop_cur_uval
+#define	tcps_slow_start_after_idle	tcps_propinfo_tbl[42].prop_cur_uval
+#define	tcps_slow_start_initial		tcps_propinfo_tbl[43].prop_cur_uval
+#define	tcps_sack_permitted		tcps_propinfo_tbl[44].prop_cur_uval
+#define	tcps_ipv6_hoplimit		tcps_propinfo_tbl[45].prop_cur_uval
+#define	tcps_mss_def_ipv6		tcps_propinfo_tbl[46].prop_cur_uval
+#define	tcps_mss_max_ipv6		tcps_propinfo_tbl[47].prop_cur_uval
+#define	tcps_rev_src_routes		tcps_propinfo_tbl[48].prop_cur_bval
+#define	tcps_local_dack_interval	tcps_propinfo_tbl[49].prop_cur_uval
+#define	tcps_local_dacks_max		tcps_propinfo_tbl[50].prop_cur_uval
+#define	tcps_ecn_permitted		tcps_propinfo_tbl[51].prop_cur_uval
+#define	tcps_rst_sent_rate_enabled	tcps_propinfo_tbl[52].prop_cur_bval
+#define	tcps_rst_sent_rate		tcps_propinfo_tbl[53].prop_cur_uval
+#define	tcps_push_timer_interval	tcps_propinfo_tbl[54].prop_cur_uval
+#define	tcps_use_smss_as_mss_opt	tcps_propinfo_tbl[55].prop_cur_bval
+#define	tcps_keepalive_abort_interval_high \
+					tcps_propinfo_tbl[56].prop_max_uval
+#define	tcps_keepalive_abort_interval \
+					tcps_propinfo_tbl[56].prop_cur_uval
+#define	tcps_keepalive_abort_interval_low \
+					tcps_propinfo_tbl[56].prop_min_uval
+#define	tcps_wroff_xtra			tcps_propinfo_tbl[57].prop_cur_uval
+#define	tcps_dev_flow_ctl		tcps_propinfo_tbl[58].prop_cur_bval
+#define	tcps_reass_timeout		tcps_propinfo_tbl[59].prop_cur_uval
 
 extern struct qinit tcp_rinitv4, tcp_rinitv6;
 extern boolean_t do_tcp_fusion;
@@ -574,6 +561,7 @@
 extern size_t	tcp_fuse_set_rcv_hiwat(tcp_t *, size_t);
 extern int	tcp_fuse_maxpsz(tcp_t *);
 extern void	tcp_fuse_backenable(tcp_t *);
+extern void	tcp_iss_key_init(uint8_t *, int, tcp_stack_t *);
 
 /*
  * Output related functions in tcp_output.c.
@@ -682,11 +670,6 @@
 extern int	tcp_cpu_update(cpu_setup_t, int, void *);
 extern void	tcp_ioctl_abort_conn(queue_t *, mblk_t *);
 extern uint32_t	tcp_find_listener_conf(tcp_stack_t *, in_port_t);
-extern int	tcp_listener_conf_get(queue_t *, mblk_t *, caddr_t, cred_t *);
-extern int	tcp_listener_conf_add(queue_t *, mblk_t *, char *, caddr_t,
-		    cred_t *);
-extern int	tcp_listener_conf_del(queue_t *, mblk_t *, char *, caddr_t,
-		    cred_t *);
 extern void	tcp_listener_conf_cleanup(tcp_stack_t *);
 
 #endif	/* _KERNEL */
--- a/usr/src/uts/common/inet/tcp_stack.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/tcp_stack.h	Fri Mar 26 17:53:11 2010 -0400
@@ -52,7 +52,7 @@
 	 */
 #define	TCP_NUM_EPRIV_PORTS	64
 	int		tcps_g_num_epriv_ports;
-	uint16_t	tcps_g_epriv_ports[TCP_NUM_EPRIV_PORTS];
+	in_port_t	tcps_g_epriv_ports[TCP_NUM_EPRIV_PORTS];
 	kmutex_t	tcps_epriv_port_lock;
 
 	/*
@@ -61,10 +61,8 @@
 	 */
 	in_port_t	tcps_min_anonpriv_port;
 
-	/* Only modified during _init and _fini thus no locking is needed. */
-	caddr_t		tcps_g_nd;
-	struct tcpparam_s *tcps_params;	/* ndd parameters */
-	struct tcpparam_s *tcps_wroff_xtra_param;
+	/* holds the tcp tunables */
+	struct mod_prop_info_s *tcps_propinfo_tbl;
 
 	/* Hint not protected by any lock */
 	uint_t		tcps_next_port_to_try;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/tunables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,444 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <inet/tunables.h>
+#include <sys/md5.h>
+#include <inet/common.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <netinet/icmp6.h>
+#include <inet/ip_stack.h>
+#include <inet/rawip_impl.h>
+#include <inet/tcp_stack.h>
+#include <inet/tcp_impl.h>
+#include <inet/udp_impl.h>
+#include <inet/sctp/sctp_stack.h>
+#include <inet/sctp/sctp_impl.h>
+#include <inet/tunables.h>
+
+static int
+prop_perm2const(mod_prop_info_t *pinfo)
+{
+	if (pinfo->mpi_setf == NULL)
+		return (MOD_PROP_PERM_READ);
+	if (pinfo->mpi_getf == NULL)
+		return (MOD_PROP_PERM_WRITE);
+	return (MOD_PROP_PERM_RW);
+}
+
+/*
+ * Modifies the value of the property to default value or to the `pval'
+ * specified by the user.
+ */
+/* ARGSUSED */
+int
+mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	char 		*end;
+	unsigned long 	new_value;
+
+	if (flags & MOD_PROP_DEFAULT) {
+		pinfo->prop_cur_bval = pinfo->prop_def_bval;
+		return (0);
+	}
+
+	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
+		return (EINVAL);
+	if (new_value != B_TRUE && new_value != B_FALSE)
+		return (EINVAL);
+	pinfo->prop_cur_bval = new_value;
+	return (0);
+}
+
+/*
+ * Retrieves property permission, default value, current value or possible
+ * values for those properties whose value type is boolean_t.
+ */
+/* ARGSUSED */
+int
+mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *pval, uint_t psize, uint_t flags)
+{
+	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
+	boolean_t	get_perm = (flags & MOD_PROP_PERM);
+	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
+	size_t		nbytes;
+
+	bzero(pval, psize);
+	if (get_perm)
+		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
+	else if (get_range)
+		nbytes = snprintf(pval, psize, "%u,%u", B_FALSE, B_TRUE);
+	else if (get_def)
+		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_bval);
+	else
+		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_bval);
+	if (nbytes >= psize)
+		return (ENOBUFS);
+	return (0);
+}
+
+/*
+ * Modifies the value of the property to default value or to the `pval'
+ * specified by the user.
+ */
+/* ARGSUSED */
+int
+mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	char 		*end;
+	unsigned long 	new_value;
+
+	if (flags & MOD_PROP_DEFAULT) {
+		pinfo->prop_cur_uval = pinfo->prop_def_uval;
+		return (0);
+	}
+
+	if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
+		return (EINVAL);
+	if (new_value < pinfo->prop_min_uval ||
+	    new_value > pinfo->prop_max_uval) {
+		return (ERANGE);
+	}
+	pinfo->prop_cur_uval = (uint32_t)new_value;
+	return (0);
+}
+
+/*
+ * Rounds up the value to make it multiple of 8.
+ */
+/* ARGSUSED */
+int
+mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* pval, uint_t flags)
+{
+	int	err;
+
+	if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
+		return (err);
+
+	/* if required, align the value to multiple of 8 */
+	if (pinfo->prop_cur_uval & 0x7) {
+		pinfo->prop_cur_uval &= ~0x7;
+		pinfo->prop_cur_uval += 0x8;
+	}
+
+	return (0);
+}
+
+/*
+ * Retrieves property permission, default value, current value or possible
+ * values for those properties whose value type is uint32_t.
+ */
+/* ARGSUSED */
+int
+mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *pval, uint_t psize, uint_t flags)
+{
+	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
+	boolean_t	get_perm = (flags & MOD_PROP_PERM);
+	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
+	size_t		nbytes;
+
+	bzero(pval, psize);
+	if (get_perm)
+		nbytes = snprintf(pval, psize, "%u", prop_perm2const(pinfo));
+	else if (get_range)
+		nbytes = snprintf(pval, psize, "%u-%u",
+		    pinfo->prop_min_uval, pinfo->prop_max_uval);
+	else if (get_def)
+		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
+	else
+		nbytes = snprintf(pval, psize, "%u", pinfo->prop_cur_uval);
+	if (nbytes >= psize)
+		return (ENOBUFS);
+	return (0);
+}
+
+/*
+ * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
+ * backward compatibility with /sbin/ndd.
+ */
+/* ARGSUSED */
+int
+mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *val, uint_t psize, uint_t flags)
+{
+	char		*pval = val;
+	mod_prop_info_t	*ptbl, *prop;
+	ip_stack_t	*ipst;
+	tcp_stack_t	*tcps;
+	sctp_stack_t	*sctps;
+	udp_stack_t	*us;
+	icmp_stack_t	*is;
+	uint_t		size;
+	size_t		nbytes = 0, tbytes = 0;
+
+	bzero(pval, psize);
+	size = psize;
+
+	switch (pinfo->mpi_proto) {
+	case MOD_PROTO_IP:
+	case MOD_PROTO_IPV4:
+	case MOD_PROTO_IPV6:
+		ipst = (ip_stack_t *)cbarg;
+		ptbl = ipst->ips_propinfo_tbl;
+		break;
+	case MOD_PROTO_RAWIP:
+		is = (icmp_stack_t *)cbarg;
+		ptbl = is->is_propinfo_tbl;
+		break;
+	case MOD_PROTO_TCP:
+		tcps = (tcp_stack_t *)cbarg;
+		ptbl = tcps->tcps_propinfo_tbl;
+		break;
+	case MOD_PROTO_UDP:
+		us = (udp_stack_t *)cbarg;
+		ptbl = us->us_propinfo_tbl;
+		break;
+	case MOD_PROTO_SCTP:
+		sctps = (sctp_stack_t *)cbarg;
+		ptbl = sctps->sctps_propinfo_tbl;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	for (prop = ptbl; prop->mpi_name != NULL; prop++) {
+		if (prop->mpi_name[0] == '\0' ||
+		    strcmp(prop->mpi_name, "mtu") == 0 ||
+		    strcmp(prop->mpi_name, "?") == 0)
+			continue;
+		nbytes = snprintf(pval, size, "%s %d %d", prop->mpi_name,
+		    prop->mpi_proto, prop_perm2const(prop));
+		size -= nbytes + 1;
+		pval += nbytes + 1;
+		tbytes += nbytes + 1;
+		if (tbytes >= psize) {
+			/* Buffer overflow, stop copying information */
+			return (ENOBUFS);
+		}
+	}
+	return (0);
+}
+
+/*
+ * Hold a lock while changing *_epriv_ports to prevent multiple
+ * threads from changing it at the same time.
+ */
+/* ARGSUSED */
+int
+mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+    const char *ifname, const void* val, uint_t flags)
+{
+	uint_t		proto = pinfo->mpi_proto;
+	tcp_stack_t	*tcps;
+	sctp_stack_t	*sctps;
+	udp_stack_t	*us;
+	unsigned long	new_value;
+	char		*end;
+	kmutex_t	*lock;
+	uint_t		i, nports;
+	in_port_t	*ports;
+	boolean_t	def = (flags & MOD_PROP_DEFAULT);
+	const char	*pval = val;
+
+	if (!def) {
+		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
+		    *end != '\0') {
+			return (EINVAL);
+		}
+
+		if (new_value < pinfo->prop_min_uval ||
+		    new_value > pinfo->prop_max_uval) {
+			return (ERANGE);
+		}
+	}
+
+	switch (proto) {
+	case MOD_PROTO_TCP:
+		tcps = (tcp_stack_t *)cbarg;
+		lock = &tcps->tcps_epriv_port_lock;
+		ports = tcps->tcps_g_epriv_ports;
+		nports = tcps->tcps_g_num_epriv_ports;
+		break;
+	case MOD_PROTO_UDP:
+		us = (udp_stack_t *)cbarg;
+		lock = &us->us_epriv_port_lock;
+		ports = us->us_epriv_ports;
+		nports = us->us_num_epriv_ports;
+		break;
+	case MOD_PROTO_SCTP:
+		sctps = (sctp_stack_t *)cbarg;
+		lock = &sctps->sctps_epriv_port_lock;
+		ports = sctps->sctps_g_epriv_ports;
+		nports = sctps->sctps_g_num_epriv_ports;
+		break;
+	default:
+		return (ENOTSUP);
+	}
+
+	mutex_enter(lock);
+
+	/* if MOD_PROP_DEFAULT is set then reset the ports list to default */
+	if (def) {
+		for (i = 0; i < nports; i++)
+			ports[i] = 0;
+		ports[0] = ULP_DEF_EPRIV_PORT1;
+		ports[1] = ULP_DEF_EPRIV_PORT2;
+		mutex_exit(lock);
+		return (0);
+	}
+
+	/* Check if the value is already in the list */
+	for (i = 0; i < nports; i++) {
+		if (new_value == ports[i])
+			break;
+	}
+
+	if (flags & MOD_PROP_REMOVE) {
+		if (i == nports) {
+			mutex_exit(lock);
+			return (ESRCH);
+		}
+		/* Clear the value */
+		ports[i] = 0;
+	} else if (flags & MOD_PROP_APPEND) {
+		if (i != nports) {
+			mutex_exit(lock);
+			return (EEXIST);
+		}
+
+		/* Find an empty slot */
+		for (i = 0; i < nports; i++) {
+			if (ports[i] == 0)
+				break;
+		}
+		if (i == nports) {
+			mutex_exit(lock);
+			return (EOVERFLOW);
+		}
+		/* Set the new value */
+		ports[i] = (in_port_t)new_value;
+	} else {
+		/*
+		 * If the user used 'assignment' modifier.
+		 * For eg:
+		 * 	# ipadm set-prop -p extra_priv_ports=3001 tcp
+		 *
+		 * We clear all the ports and then just add 3001.
+		 */
+		ASSERT(flags == MOD_PROP_ACTIVE);
+		for (i = 0; i < nports; i++)
+			ports[i] = 0;
+		ports[0] = (in_port_t)new_value;
+	}
+
+	mutex_exit(lock);
+	return (0);
+}
+
+/*
+ * Note: No locks are held when inspecting *_epriv_ports
+ * but instead the code relies on:
+ * - the fact that the address of the array and its size never changes
+ * - the atomic assignment of the elements of the array
+ */
+/* ARGSUSED */
+int
+mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+    void *val, uint_t psize, uint_t flags)
+{
+	uint_t		proto = pinfo->mpi_proto;
+	tcp_stack_t	*tcps;
+	sctp_stack_t	*sctps;
+	udp_stack_t	*us;
+	uint_t		i, nports, size;
+	in_port_t	*ports;
+	char		*pval = val;
+	size_t		nbytes = 0, tbytes = 0;
+	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
+	boolean_t	get_perm = (flags & MOD_PROP_PERM);
+	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
+
+	bzero(pval, psize);
+	size = psize;
+
+	if (get_def) {
+		tbytes = snprintf(pval, psize, "%u,%u", ULP_DEF_EPRIV_PORT1,
+		    ULP_DEF_EPRIV_PORT2);
+		goto ret;
+	} else if (get_perm) {
+		tbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
+		goto ret;
+	}
+
+	switch (proto) {
+	case MOD_PROTO_TCP:
+		tcps = (tcp_stack_t *)cbarg;
+		ports = tcps->tcps_g_epriv_ports;
+		nports = tcps->tcps_g_num_epriv_ports;
+		break;
+	case MOD_PROTO_UDP:
+		us = (udp_stack_t *)cbarg;
+		ports = us->us_epriv_ports;
+		nports = us->us_num_epriv_ports;
+		break;
+	case MOD_PROTO_SCTP:
+		sctps = (sctp_stack_t *)cbarg;
+		ports = sctps->sctps_g_epriv_ports;
+		nports = sctps->sctps_g_num_epriv_ports;
+		break;
+	default:
+		return (ENOTSUP);
+	}
+
+	if (get_range) {
+		tbytes = snprintf(pval, psize, "%u-%u", pinfo->prop_min_uval,
+		    pinfo->prop_max_uval);
+		goto ret;
+	}
+
+	for (i = 0; i < nports; i++) {
+		if (ports[i] != 0) {
+			if (psize == size)
+				nbytes = snprintf(pval, size, "%u", ports[i]);
+			else
+				nbytes = snprintf(pval, size, ",%u", ports[i]);
+			size -= nbytes;
+			pval += nbytes;
+			tbytes += nbytes;
+			if (tbytes >= psize)
+				return (ENOBUFS);
+		}
+	}
+	return (0);
+ret:
+	if (tbytes >= psize)
+		return (ENOBUFS);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/tunables.h	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,163 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _INET_TUNABLES_H
+#define	_INET_TUNABLES_H
+
+#include <sys/types.h>
+#include <net/if.h>
+#ifdef _KERNEL
+#include <sys/netstack.h>
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	MAXPROPNAMELEN	64
+
+/*
+ * The `mod_ioc_prop_s' datastructure is used as an IOCTL argument for
+ * SIOCSETPROP and SIOCGETPROP ioctls. This datastructure identifies the
+ * protocol (`mpr_proto') property (`mpr_name'), which needs to be modified
+ * or retrieved (`mpr_valsize' and `mpr_val'). If the property applies to an
+ * interface then `mpr_ifname' contains the name of the interface.
+ */
+typedef struct mod_ioc_prop_s {
+	uint_t		mpr_version;
+	uint_t		mpr_flags;			/* see below */
+	/* name of the interface (ill) for which property will be applied */
+	char		mpr_ifname[LIFNAMSIZ];
+	uint_t		mpr_proto;			/* see below */
+	char		mpr_name[MAXPROPNAMELEN];	/* property name */
+	uint_t		mpr_valsize;			/* size of mpr_val */
+	char		mpr_val[1];
+} mod_ioc_prop_t;
+
+#define	MOD_PROP_VERSION	1
+
+/* permission flags for properties */
+#define	MOD_PROP_PERM_READ	0x1
+#define	MOD_PROP_PERM_WRITE	0x2
+#define	MOD_PROP_PERM_RW	(MOD_PROP_PERM_READ|MOD_PROP_PERM_WRITE)
+
+/* mpr_flags values */
+#define	MOD_PROP_ACTIVE		0x01	/* current value of the property */
+#define	MOD_PROP_DEFAULT	0x02	/* default value of the property */
+#define	MOD_PROP_POSSIBLE	0x04	/* possible values for the property */
+#define	MOD_PROP_PERM		0x08	/* read/write permission for property */
+#define	MOD_PROP_APPEND		0x10	/* append to multi-valued property */
+#define	MOD_PROP_REMOVE		0x20	/* remove from multi-valued property */
+
+/* mpr_proto values */
+#define	MOD_PROTO_NONE		0x00
+#define	MOD_PROTO_IPV4		0x01	/* property is applicable to IPV4 */
+#define	MOD_PROTO_IPV6		0x02	/* property is applicable to IPV6 */
+#define	MOD_PROTO_RAWIP		0x04	/* property is applicable to ICMP */
+#define	MOD_PROTO_TCP		0x08	/* property is applicable to TCP */
+#define	MOD_PROTO_UDP		0x10	/* property is applicable to UDP */
+#define	MOD_PROTO_SCTP		0x20	/* property is applicable to SCTP */
+
+/* property is applicable to both IPV[4|6] */
+#define	MOD_PROTO_IP		(MOD_PROTO_IPV4|MOD_PROTO_IPV6)
+
+#ifdef	_KERNEL
+
+typedef struct mod_prop_info_s mod_prop_info_t;
+
+/* set/get property callback functions */
+typedef int	mod_prop_setf_t(void *, cred_t *, mod_prop_info_t *,
+		    const char *, const void *, uint_t);
+typedef int	mod_prop_getf_t(void *, mod_prop_info_t *, const char *,
+		    void *val, uint_t, uint_t);
+
+typedef struct mod_propval_uint32_s {
+	uint32_t	mod_propval_umin;
+	uint32_t	mod_propval_umax;
+	uint32_t	mod_propval_ucur;
+} mod_propval_uint32_t;
+
+/*
+ * protocol property information
+ */
+struct mod_prop_info_s {
+	char			*mpi_name;	/* property name */
+	uint_t			mpi_proto;	/* property protocol */
+	mod_prop_setf_t		*mpi_setf;	/* sets the property value */
+	mod_prop_getf_t		*mpi_getf;	/* gets the property value */
+	/*
+	 * Holds the current value of the property. Whenever applicable
+	 * holds the min/max value too.
+	 */
+	union {
+		mod_propval_uint32_t	mpi_uval;
+		boolean_t		mpi_bval;
+		uint64_t		_pad[2];
+	} u;
+	/*
+	 * Holds the default value of the property, that is value of
+	 * the property at boot time.
+	 */
+	union {
+		uint32_t	mpi_def_uval;
+		boolean_t	mpi_def_bval;
+	} u_def;
+};
+
+/* shortcuts to access current/default values */
+#define	prop_min_uval	u.mpi_uval.mod_propval_umin
+#define	prop_max_uval	u.mpi_uval.mod_propval_umax
+#define	prop_cur_uval	u.mpi_uval.mod_propval_ucur
+#define	prop_cur_bval	u.mpi_bval
+#define	prop_def_uval	u_def.mpi_def_uval
+#define	prop_def_bval	u_def.mpi_def_bval
+
+#define	MS		1L
+#define	SECONDS		(1000 * MS)
+#define	MINUTES		(60 * SECONDS)
+#define	HOURS		(60 * MINUTES)
+#define	DAYS		(24 * HOURS)
+
+/* Largest TCP/UDP/SCTP port number */
+#define	ULP_MAX_PORT	(64 * 1024 - 1)
+
+/* extra privilege ports for upper layer protocols, tcp, sctp and udp */
+#define	ULP_DEF_EPRIV_PORT1	2049
+#define	ULP_DEF_EPRIV_PORT2	4045
+
+/* generic function to set/get global module properties */
+extern mod_prop_setf_t	mod_set_boolean, mod_set_uint32,
+			mod_set_aligned, mod_set_extra_privports;
+
+extern mod_prop_getf_t	mod_get_boolean, mod_get_uint32,
+			mod_get_allprop, mod_get_extra_privports;
+
+#endif	/* _KERNEL */
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _INET_TUNABLES_H */
--- a/usr/src/uts/common/inet/udp/udp.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/udp/udp.c	Fri Mar 26 17:53:11 2010 -0400
@@ -68,7 +68,6 @@
 #include <inet/ip_ndp.h>
 #include <inet/proto_set.h>
 #include <inet/mib2.h>
-#include <inet/nd.h>
 #include <inet/optcom.h>
 #include <inet/snmpcom.h>
 #include <inet/kstatcom.h>
@@ -165,10 +164,6 @@
 static int	udp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin,
 		    sin6_t *sin6, ushort_t ipversion, cred_t *cr, pid_t,
 		    ip_xmit_attr_t *ixa);
-static int	udp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr);
-static boolean_t udp_param_register(IDP *ndp, udpparam_t *udppa, int cnt);
-static int	udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-		    cred_t *cr);
 static mblk_t	*udp_prepend_hdr(conn_t *, ip_xmit_attr_t *, const ip_pkt_t *,
     const in6_addr_t *, const in6_addr_t *, in_port_t, uint32_t, mblk_t *,
     int *);
@@ -211,11 +206,6 @@
 static int	udp_do_connect(conn_t *, const struct sockaddr *, socklen_t,
     cred_t *, pid_t);
 
-#define	UDP_RECV_HIWATER	(56 * 1024)
-#define	UDP_RECV_LOWATER	128
-#define	UDP_XMIT_HIWATER	(56 * 1024)
-#define	UDP_XMIT_LOWATER	1024
-
 #pragma inline(udp_output_connected, udp_output_newdst, udp_output_lastdst)
 
 /*
@@ -336,32 +326,11 @@
 	(XPG4_1|SENDZERO) /* PROVIDER_flag */
 };
 
-/* largest UDP port number */
-#define	UDP_MAX_PORT	65535
-
 /*
- * Table of ND variables supported by udp.  These are loaded into us_nd
- * in udp_open.
- * All of these are alterable, within the min/max values given, at run time.
+ * UDP tunables related declarations. Definitions are in udp_tunables.c
  */
-/* BEGIN CSTYLED */
-udpparam_t udp_param_arr[] = {
- /*min		max		value		name */
- { 0L,		256,		32,		"udp_wroff_extra" },
- { 1L,		255,		255,		"udp_ipv4_ttl" },
- { 0,		IPV6_MAX_HOPS,	IPV6_DEFAULT_HOPS, "udp_ipv6_hoplimit"},
- { 1024,	(32 * 1024),	1024,		"udp_smallest_nonpriv_port" },
- { 0,		1,		1,		"udp_do_checksum" },
- { 1024,	UDP_MAX_PORT,	(32 * 1024),	"udp_smallest_anon_port" },
- { 1024,	UDP_MAX_PORT,	UDP_MAX_PORT,	"udp_largest_anon_port" },
- { UDP_XMIT_LOWATER, (1<<30), UDP_XMIT_HIWATER,	"udp_xmit_hiwat"},
- { 0,		     (1<<30), UDP_XMIT_LOWATER, "udp_xmit_lowat"},
- { UDP_RECV_LOWATER, (1<<30), UDP_RECV_HIWATER,	"udp_recv_hiwat"},
- { 65536,	(1<<30),	2*1024*1024,	"udp_max_buf"},
- { 0,		1,		0,		"udp_pmtu_discovery" },
- { 0,		1,		0,		"udp_sendto_ignerr" },
-};
-/* END CSTYLED */
+extern mod_prop_info_t udp_propinfo_tbl[];
+extern int udp_propinfo_count;
 
 /* Setable in /etc/system */
 /* If set to 0, pick ephemeral port sequentially; otherwise randomly. */
@@ -912,93 +881,6 @@
 	}
 }
 
-/*ARGSUSED2*/
-static int
-udp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	int i;
-	udp_t		*udp = Q_TO_UDP(q);
-	udp_stack_t *us = udp->udp_us;
-
-	for (i = 0; i < us->us_num_epriv_ports; i++) {
-		if (us->us_epriv_ports[i] != 0)
-			(void) mi_mpprintf(mp, "%d ", us->us_epriv_ports[i]);
-	}
-	return (0);
-}
-
-/* ARGSUSED1 */
-static int
-udp_extra_priv_ports_add(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	udp_t		*udp = Q_TO_UDP(q);
-	udp_stack_t *us = udp->udp_us;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value <= 0 || new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	/* Check if the value is already in the list */
-	for (i = 0; i < us->us_num_epriv_ports; i++) {
-		if (new_value == us->us_epriv_ports[i]) {
-			return (EEXIST);
-		}
-	}
-	/* Find an empty slot */
-	for (i = 0; i < us->us_num_epriv_ports; i++) {
-		if (us->us_epriv_ports[i] == 0)
-			break;
-	}
-	if (i == us->us_num_epriv_ports) {
-		return (EOVERFLOW);
-	}
-
-	/* Set the new value */
-	us->us_epriv_ports[i] = (in_port_t)new_value;
-	return (0);
-}
-
-/* ARGSUSED1 */
-static int
-udp_extra_priv_ports_del(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
-    cred_t *cr)
-{
-	long	new_value;
-	int	i;
-	udp_t		*udp = Q_TO_UDP(q);
-	udp_stack_t *us = udp->udp_us;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * port number limits.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value <= 0 || new_value >= 65536) {
-		return (EINVAL);
-	}
-
-	/* Check that the value is already in the list */
-	for (i = 0; i < us->us_num_epriv_ports; i++) {
-		if (us->us_epriv_ports[i] == new_value)
-			break;
-	}
-	if (i == us->us_num_epriv_ports) {
-		return (ESRCH);
-	}
-
-	/* Clear the value */
-	us->us_epriv_ports[i] = 0;
-	return (0);
-}
-
 /* At minimum we need 4 bytes of UDP header */
 #define	ICMP_MIN_UDP_HDR	4
 
@@ -2225,79 +2107,6 @@
 	return (0);
 }
 
-/*
- * This routine retrieves the value of an ND variable in a udpparam_t
- * structure.  It is called through nd_getset when a user reads the
- * variable.
- */
-/* ARGSUSED */
-static int
-udp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr)
-{
-	udpparam_t *udppa = (udpparam_t *)cp;
-
-	(void) mi_mpprintf(mp, "%d", udppa->udp_param_value);
-	return (0);
-}
-
-/*
- * Walk through the param array specified registering each element with the
- * named dispatch (ND) handler.
- */
-static boolean_t
-udp_param_register(IDP *ndp, udpparam_t *udppa, int cnt)
-{
-	for (; cnt-- > 0; udppa++) {
-		if (udppa->udp_param_name && udppa->udp_param_name[0]) {
-			if (!nd_load(ndp, udppa->udp_param_name,
-			    udp_param_get, udp_param_set,
-			    (caddr_t)udppa)) {
-				nd_free(ndp);
-				return (B_FALSE);
-			}
-		}
-	}
-	if (!nd_load(ndp, "udp_extra_priv_ports",
-	    udp_extra_priv_ports_get, NULL, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "udp_extra_priv_ports_add",
-	    NULL, udp_extra_priv_ports_add, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	if (!nd_load(ndp, "udp_extra_priv_ports_del",
-	    NULL, udp_extra_priv_ports_del, NULL)) {
-		nd_free(ndp);
-		return (B_FALSE);
-	}
-	return (B_TRUE);
-}
-
-/* This routine sets an ND variable in a udpparam_t structure. */
-/* ARGSUSED */
-static int
-udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr)
-{
-	long		new_value;
-	udpparam_t	*udppa = (udpparam_t *)cp;
-
-	/*
-	 * Fail the request if the new value does not lie within the
-	 * required bounds.
-	 */
-	if (ddi_strtol(value, NULL, 10, &new_value) != 0 ||
-	    new_value < udppa->udp_param_min ||
-	    new_value > udppa->udp_param_max) {
-		return (EINVAL);
-	}
-
-	/* Set the new value */
-	udppa->udp_param_value = new_value;
-	return (0);
-}
-
 static mblk_t *
 udp_queue_fallback(udp_t *udp, mblk_t *mp)
 {
@@ -4521,7 +4330,6 @@
 	struct iocblk *iocp;
 	conn_t	*connp = Q_TO_CONN(q);
 	udp_t	*udp = connp->conn_udp;
-	udp_stack_t *us = udp->udp_us;
 	cred_t	*cr;
 
 	switch (mp->b_datap->db_type) {
@@ -4655,14 +4463,6 @@
 			mi_copyin(q, mp, NULL,
 			    SIZEOF_STRUCT(strbuf, iocp->ioc_flag));
 			return;
-		case ND_SET:
-			/* nd_getset performs the necessary checking */
-		case ND_GET:
-			if (nd_getset(q, us->us_nd, mp)) {
-				qreply(q, mp);
-				return;
-			}
-			break;
 		case _SIOCSOCKFALLBACK:
 			/*
 			 * Either sockmod is about to be popped and the
@@ -4826,17 +4626,18 @@
 udp_stack_init(netstackid_t stackid, netstack_t *ns)
 {
 	udp_stack_t	*us;
-	udpparam_t	*pa;
 	int		i;
 	int		error = 0;
 	major_t		major;
+	size_t		arrsz;
 
 	us = (udp_stack_t *)kmem_zalloc(sizeof (*us), KM_SLEEP);
 	us->us_netstack = ns;
 
+	mutex_init(&us->us_epriv_port_lock, NULL, MUTEX_DEFAULT, NULL);
 	us->us_num_epriv_ports = UDP_NUM_EPRIV_PORTS;
-	us->us_epriv_ports[0] = 2049;
-	us->us_epriv_ports[1] = 4045;
+	us->us_epriv_ports[0] = ULP_DEF_EPRIV_PORT1;
+	us->us_epriv_ports[1] = ULP_DEF_EPRIV_PORT2;
 
 	/*
 	 * The smallest anonymous port in the priviledged port range which UDP
@@ -4862,13 +4663,10 @@
 		    NULL);
 	}
 
-	pa = (udpparam_t *)kmem_alloc(sizeof (udp_param_arr), KM_SLEEP);
-
-	us->us_param_arr = pa;
-	bcopy(udp_param_arr, us->us_param_arr, sizeof (udp_param_arr));
-
-	(void) udp_param_register(&us->us_nd,
-	    us->us_param_arr, A_CNT(udp_param_arr));
+	arrsz = udp_propinfo_count * sizeof (mod_prop_info_t);
+	us->us_propinfo_tbl = (mod_prop_info_t *)kmem_alloc(arrsz,
+	    KM_SLEEP);
+	bcopy(udp_propinfo_tbl, us->us_propinfo_tbl, arrsz);
 
 	us->us_kstat = udp_kstat2_init(stackid, &us->us_statistics);
 	us->us_mibkp = udp_kstat_init(stackid);
@@ -4897,9 +4695,9 @@
 
 	us->us_bind_fanout = NULL;
 
-	nd_free(&us->us_nd);
-	kmem_free(us->us_param_arr, sizeof (udp_param_arr));
-	us->us_param_arr = NULL;
+	kmem_free(us->us_propinfo_tbl,
+	    udp_propinfo_count * sizeof (mod_prop_info_t));
+	us->us_propinfo_tbl = NULL;
 
 	udp_kstat_fini(stackid, us->us_mibkp);
 	us->us_mibkp = NULL;
@@ -4908,6 +4706,7 @@
 	us->us_kstat = NULL;
 	bzero(&us->us_statistics, sizeof (us->us_statistics));
 
+	mutex_destroy(&us->us_epriv_port_lock);
 	ldi_ident_release(us->us_ldi_ident);
 	kmem_free(us, sizeof (*us));
 }
@@ -6944,8 +6743,6 @@
 	}
 
 	switch (cmd) {
-		case ND_SET:
-		case ND_GET:
 		case _SIOCSOCKFALLBACK:
 		case TI_GETPEERNAME:
 		case TI_GETMYNAME:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/inet/udp/udp_tunables.c	Fri Mar 26 17:53:11 2010 -0400
@@ -0,0 +1,104 @@
+/*
+ * CDDL HEADER START
+ *
+ * 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]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/udp_impl.h>
+#include <sys/sunddi.h>
+
+/*
+ * All of these are alterable, within the min/max values given, at run time.
+ *
+ * Note: All those tunables which do not start with "udp_" are Committed and
+ * therefore are public. See PSARC 2009/306.
+ */
+mod_prop_info_t udp_propinfo_tbl[] = {
+	/* tunable - 0 */
+	{ "udp_wroff_extra", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, 256, 32}, {32} },
+
+	{ "udp_ipv4_ttl", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1, 255, 255}, {255} },
+
+	{ "udp_ipv6_hoplimit", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS}, {IPV6_DEFAULT_HOPS} },
+
+	{ "smallest_nonpriv_port", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, (32 * 1024), 1024}, {1024} },
+
+	{ "udp_do_checksum", MOD_PROTO_UDP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_TRUE}, {B_TRUE} },
+
+	{ "smallest_anon_port", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, (32 * 1024)}, {(32 * 1024)} },
+
+	{ "largest_anon_port", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {1024, ULP_MAX_PORT, ULP_MAX_PORT}, {ULP_MAX_PORT} },
+
+	{ "send_maxbuf", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {UDP_XMIT_LOWATER, (1<<30), UDP_XMIT_HIWATER},
+	    {UDP_XMIT_HIWATER} },
+
+	{ "udp_xmit_lowat", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {0, (1<<30), UDP_XMIT_LOWATER},
+	    {UDP_XMIT_LOWATER} },
+
+	{ "recv_maxbuf", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {UDP_RECV_LOWATER, (1<<30), UDP_RECV_HIWATER},
+	    {UDP_RECV_HIWATER} },
+
+	/* tunable - 10 */
+	{ "udp_max_buf", MOD_PROTO_UDP,
+	    mod_set_uint32, mod_get_uint32,
+	    {65536, (1<<30), 2*1024*1024}, {2*1024*1024} },
+
+	{ "udp_pmtu_discovery", MOD_PROTO_UDP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "udp_sendto_ignerr", MOD_PROTO_UDP,
+	    mod_set_boolean, mod_get_boolean,
+	    {B_FALSE}, {B_FALSE} },
+
+	{ "extra_priv_ports", MOD_PROTO_UDP,
+	    mod_set_extra_privports, mod_get_extra_privports,
+	    {1, ULP_MAX_PORT, 0}, {0} },
+
+	{ "?", MOD_PROTO_UDP, NULL, mod_get_allprop, {0}, {0} },
+
+	{ NULL, 0, NULL, NULL, {0}, {0} }
+};
+
+int udp_propinfo_count = A_CNT(udp_propinfo_tbl);
--- a/usr/src/uts/common/inet/udp_impl.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/inet/udp_impl.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -48,6 +48,7 @@
 #include <inet/common.h>
 #include <inet/ip.h>
 #include <inet/optcom.h>
+#include <inet/tunables.h>
 
 #define	UDP_MOD_ID		5607
 
@@ -89,15 +90,13 @@
 
 } udp_stat_t;
 
-/* Named Dispatch Parameter Management Structure */
-typedef struct udpparam_s {
-	uint32_t udp_param_min;
-	uint32_t udp_param_max;
-	uint32_t udp_param_value;
-	char	*udp_param_name;
-} udpparam_t;
+#define	UDP_NUM_EPRIV_PORTS	64
 
-#define	UDP_NUM_EPRIV_PORTS	64
+/* Default buffer size and flow control wake up threshold. */
+#define	UDP_RECV_HIWATER	(56 * 1024)
+#define	UDP_RECV_LOWATER	128
+#define	UDP_XMIT_HIWATER	(56 * 1024)
+#define	UDP_XMIT_LOWATER	1024
 
 /*
  * UDP stack instances
@@ -110,12 +109,13 @@
 
 	int		us_num_epriv_ports;
 	in_port_t	us_epriv_ports[UDP_NUM_EPRIV_PORTS];
+	kmutex_t	us_epriv_port_lock;
 
 	/* Hint not protected by any lock */
 	in_port_t	us_next_port_to_try;
 
-	IDP		us_nd;	/* Points to table of UDP ND variables. */
-	udpparam_t	*us_param_arr; 	/* ndd variable table */
+	/* UDP tunables table */
+	struct mod_prop_info_s	*us_propinfo_tbl;
 
 	kstat_t		*us_mibkp;	/* kstats exporting mib data */
 	kstat_t		*us_kstat;
@@ -181,20 +181,19 @@
 	uint16_t	uha_checksum;		/* UDP checksum */
 } udpha_t;
 
-#define	us_wroff_extra			us_param_arr[0].udp_param_value
-#define	us_ipv4_ttl			us_param_arr[1].udp_param_value
-#define	us_ipv6_hoplimit		us_param_arr[2].udp_param_value
-#define	us_smallest_nonpriv_port	us_param_arr[3].udp_param_value
-#define	us_do_checksum			us_param_arr[4].udp_param_value
-#define	us_smallest_anon_port		us_param_arr[5].udp_param_value
-#define	us_largest_anon_port		us_param_arr[6].udp_param_value
-#define	us_xmit_hiwat			us_param_arr[7].udp_param_value
-#define	us_xmit_lowat			us_param_arr[8].udp_param_value
-#define	us_recv_hiwat			us_param_arr[9].udp_param_value
-#define	us_max_buf			us_param_arr[10].udp_param_value
-#define	us_pmtu_discovery		us_param_arr[11].udp_param_value
-#define	us_sendto_ignerr		us_param_arr[12].udp_param_value
-
+#define	us_wroff_extra			us_propinfo_tbl[0].prop_cur_uval
+#define	us_ipv4_ttl			us_propinfo_tbl[1].prop_cur_uval
+#define	us_ipv6_hoplimit		us_propinfo_tbl[2].prop_cur_uval
+#define	us_smallest_nonpriv_port	us_propinfo_tbl[3].prop_cur_uval
+#define	us_do_checksum			us_propinfo_tbl[4].prop_cur_bval
+#define	us_smallest_anon_port		us_propinfo_tbl[5].prop_cur_uval
+#define	us_largest_anon_port		us_propinfo_tbl[6].prop_cur_uval
+#define	us_xmit_hiwat			us_propinfo_tbl[7].prop_cur_uval
+#define	us_xmit_lowat			us_propinfo_tbl[8].prop_cur_uval
+#define	us_recv_hiwat			us_propinfo_tbl[9].prop_cur_uval
+#define	us_max_buf			us_propinfo_tbl[10].prop_cur_uval
+#define	us_pmtu_discovery		us_propinfo_tbl[11].prop_cur_bval
+#define	us_sendto_ignerr		us_propinfo_tbl[12].prop_cur_bval
 
 #define	UDP_STAT(us, x)		((us)->us_statistics.x.value.ui64++)
 #define	UDP_STAT_UPDATE(us, x, n)	\
--- a/usr/src/uts/common/io/strplumb.c	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/io/strplumb.c	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -123,8 +123,6 @@
 #define	TCP6		"tcp6"
 #define	UDP		"udp"
 #define	UDP6		"udp6"
-#define	SCTP		"sctp"
-#define	SCTP6		"sctp6"
 #define	ICMP		"icmp"
 #define	ICMP6		"icmp6"
 #define	IP		"ip"
@@ -134,7 +132,6 @@
 #define	UDPDEV		"/devices/pseudo/udp@0:udp"
 #define	TCP6DEV		"/devices/pseudo/tcp6@0:tcp6"
 #define	UDP6DEV		"/devices/pseudo/udp6@0:udp6"
-#define	SCTP6DEV	"/devices/pseudo/sctp6@0:sctp6"
 #define	IP6DEV		"/devices/pseudo/ip6@0:ip6"
 
 typedef struct strplumb_modspec {
@@ -150,8 +147,6 @@
 	{ "drv", TCP6 },
 	{ "drv", UDP },
 	{ "drv", UDP6 },
-	{ "drv", SCTP },
-	{ "drv", SCTP6 },
 	{ "drv", ICMP },
 	{ "drv", ICMP6 },
 	{ "drv", ARP },
--- a/usr/src/uts/common/net/if.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/net/if.h	Fri Mar 26 17:53:11 2010 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -170,13 +170,15 @@
 #define	IFF_IPMP	0x8000000000ll	/* IPMP IP interface */
 #define	IFF_VRRP	0x10000000000ll	/* Managed by VRRP */
 
+#define	IFF_NOLINKLOCAL	0x20000000000ll	/* No default linklocal */
+
 /* flags that cannot be changed by userland on any interface */
 #define	IFF_CANTCHANGE \
 	(IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING | IFF_PROMISC | \
 	IFF_MULTICAST | IFF_MULTI_BCAST | IFF_UNNUMBERED | IFF_IPV4 | \
 	IFF_IPV6 | IFF_IPMP | IFF_FIXEDMTU | IFF_VIRTUAL | \
 	IFF_LOOPBACK | IFF_ALLMULTI | IFF_DUPLICATE | IFF_COS_ENABLED | \
-	IFF_VRRP)
+	IFF_VRRP | IFF_NOLINKLOCAL)
 
 /* flags that cannot be changed by userland on an IPMP interface */
 #define	IFF_IPMP_CANTCHANGE 	IFF_FAILED
@@ -378,6 +380,7 @@
 		char	lifru_groupname[LIFGRNAMSIZ]; /* SIOC[GS]LIFGROUPNAME */
 		char	lifru_binding[LIFNAMSIZ]; /* SIOCGLIFBINDING */
 		zoneid_t lifru_zoneid;		/* SIOC[GS]LIFZONE */
+		uint_t	lifru_dadstate;		/* SIOCGLIFDADSTATE */
 	} lifr_lifru;
 
 #define	lifr_addr	lifr_lifru.lifru_addr	/* address */
@@ -396,6 +399,7 @@
 #define	lifr_groupname	lifr_lifru.lifru_groupname
 #define	lifr_binding	lifr_lifru.lifru_binding
 #define	lifr_zoneid	lifr_lifru.lifru_zoneid
+#define	lifr_dadstate	lifr_lifru.lifru_dadstate
 };
 #endif /* defined(_INT64_TYPE) */
 
@@ -421,6 +425,12 @@
 	uint_t			slr_pad;
 };
 
+/* Argument structure for SIOCGLIFDADSTATE ioctl */
+typedef enum {
+	DAD_IN_PROGRESS	= 0x1,
+	DAD_DONE	= 0x2
+} glif_dad_state_t;
+
 /*
  * OBSOLETE: Replaced by struct lifreq. Supported for compatibility.
  *
@@ -561,6 +571,7 @@
 #define	LIFC_ALLZONES	0x08		/* Include all zones */
 					/* (must be issued from global zone) */
 #define	LIFC_UNDER_IPMP	0x10		/* Include underlying IPMP interfaces */
+#define	LIFC_ENABLED	0x20		/* Include only IFF_UP interfaces */
 
 #if defined(_SYSCALL32)
 
--- a/usr/src/uts/common/sys/sockio.h	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/common/sys/sockio.h	Fri Mar 26 17:53:11 2010 -0400
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -318,6 +318,25 @@
  */
 #define	SIOCILB		_IOWR('i', 187, 0)
 
+/*
+ * IOCTL's to get/set module specific or interface specific properties.
+ * Argument is a struct mod_ioc_prop_s. These ioctls are Consolidation Private.
+ */
+#define	SIOCGETPROP	_IOWRN('p', 188, 0)
+#define	SIOCSETPROP	_IOW('p', 189, 0)
+
+/*
+ * IOCTL used to check for the given ipif, whether DAD is in progress or
+ * DAD has completed. This ioctl is Consolidation Private.
+ */
+#define	SIOCGLIFDADSTATE	_IOWR('i', 190, struct lifreq)
+
+/*
+ * IOCTL used to generate an IPv6 address using the given prefix and the
+ * default token for the interface.
+ */
+#define	SIOCSLIFPREFIX		_IOWR('i', 191, struct lifreq)
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/intel/Makefile.intel.shared	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Fri Mar 26 17:53:11 2010 -0400
@@ -318,8 +318,6 @@
 DRV_KMODS	+= rwd
 DRV_KMODS	+= rwn
 DRV_KMODS	+= sad
-DRV_KMODS	+= sctp
-DRV_KMODS	+= sctp6
 DRV_KMODS	+= sd
 DRV_KMODS	+= sdcard
 DRV_KMODS	+= sdhost
--- a/usr/src/uts/intel/ip/ip.global-objs.debug64	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/intel/ip/ip.global-objs.debug64	Fri Mar 26 17:53:11 2010 -0400
@@ -76,7 +76,7 @@
 icmp_mod_info
 icmp_opt_arr
 icmp_opt_obj
-icmp_param_arr
+icmp_propinfo_tbl
 icmp_valid_levels_arr
 icmpinfov4
 icmpinfov6
@@ -128,6 +128,8 @@
 ip_ndx_ioctl_table
 ip_poll_normal_ms
 ip_poll_normal_ticks
+ip_propinfo_tbl
+ip_propinfo_count
 ip_rput_pullups
 ip_six_byte_all_ones
 ip_squeue_create_callback
@@ -161,14 +163,12 @@
 ipsec_sel_cache
 ipsec_spd_hashsize
 ipsec_weird_null_inbound_policy
-ipv4_forward_suffix
 ipv4info
 ipv6_all_hosts_mcast
 ipv6_all_ones
 ipv6_all_rtrs_mcast
 ipv6_all_v2rtrs_mcast
 ipv6_all_zeros
-ipv6_forward_suffix
 ipv6_ll_template
 ipv6_loopback
 ipv6_solicited_node_mcast
@@ -180,12 +180,7 @@
 ire_null
 ire_nv_arr
 ire_nv_tbl
-lcl_ndp_arr
 lcl_param_arr
-lcl_sctp_param_arr
-lcl_sctp_wroff_xtra_param
-lcl_tcp_param_arr
-lcl_tcp_wroff_xtra_param
 mask_rnhead
 max_keylen
 modldrv
@@ -224,18 +219,16 @@
 sctp_kmem_faddr_cache
 sctp_kmem_ftsn_set_cache
 sctp_kmem_set_cache
-sctp_mod_info
 sctp_opt_arr
 sctp_opt_arr_size
+sctp_propinfo_tbl
+sctp_propinfo_count
 sctp_recvq_tq_task_max
 sctp_recvq_tq_task_min
 sctp_recvq_tq_thr_max
 sctp_recvq_tq_thr_min
 sctp_sin6_null
 sctpdebug
-sctpinfo
-sctprinit
-sctpwinit
 sin6_null
 sin_null
 skip_sctp_cksum
@@ -272,6 +265,8 @@
 tcp_opt_arr
 tcp_opt_obj
 tcp_outbound_squeue_switch
+tcp_propinfo_tbl
+tcp_propinfo_count
 tcp_random_anon_port
 tcp_random_end_ptr
 tcp_random_fptr
@@ -308,7 +303,8 @@
 udp_mod_info
 udp_opt_arr
 udp_opt_obj
-udp_param_arr
+udp_propinfo_tbl
+udp_propinfo_count
 udp_random_anon_port
 udp_rinitv4
 udp_rinitv6
--- a/usr/src/uts/intel/ip/ip.global-objs.obj64	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/intel/ip/ip.global-objs.obj64	Fri Mar 26 17:53:11 2010 -0400
@@ -76,7 +76,7 @@
 icmp_mod_info
 icmp_opt_arr
 icmp_opt_obj
-icmp_param_arr
+icmp_propinfo_tbl
 icmp_valid_levels_arr
 icmpinfov4
 icmpinfov6
@@ -128,6 +128,8 @@
 ip_ndx_ioctl_table
 ip_poll_normal_ms
 ip_poll_normal_ticks
+ip_propinfo_tbl
+ip_propinfo_count
 ip_rput_pullups
 ip_six_byte_all_ones
 ip_squeue_create_callback
@@ -161,14 +163,12 @@
 ipsec_sel_cache
 ipsec_spd_hashsize
 ipsec_weird_null_inbound_policy
-ipv4_forward_suffix
 ipv4info
 ipv6_all_hosts_mcast
 ipv6_all_ones
 ipv6_all_rtrs_mcast
 ipv6_all_v2rtrs_mcast
 ipv6_all_zeros
-ipv6_forward_suffix
 ipv6_ll_template
 ipv6_loopback
 ipv6_solicited_node_mcast
@@ -180,12 +180,7 @@
 ire_null
 ire_nv_arr
 ire_nv_tbl
-lcl_ndp_arr
 lcl_param_arr
-lcl_sctp_param_arr
-lcl_sctp_wroff_xtra_param
-lcl_tcp_param_arr
-lcl_tcp_wroff_xtra_param
 mask_rnhead
 max_keylen
 modldrv
@@ -222,18 +217,16 @@
 sctp_kmem_faddr_cache
 sctp_kmem_ftsn_set_cache
 sctp_kmem_set_cache
-sctp_mod_info
 sctp_opt_arr
 sctp_opt_arr_size
+sctp_propinfo_tbl
+sctp_propinfo_count
 sctp_recvq_tq_task_max
 sctp_recvq_tq_task_min
 sctp_recvq_tq_thr_max
 sctp_recvq_tq_thr_min
 sctp_sin6_null
 sctpdebug
-sctpinfo
-sctprinit
-sctpwinit
 sin6_null
 sin_null
 sock_rawip_downcalls
@@ -269,6 +262,8 @@
 tcp_opt_arr
 tcp_opt_obj
 tcp_outbound_squeue_switch
+tcp_propinfo_tbl
+tcp_propinfo_count
 tcp_random_anon_port
 tcp_random_end_ptr
 tcp_random_fptr
@@ -305,7 +300,8 @@
 udp_mod_info
 udp_opt_arr
 udp_opt_obj
-udp_param_arr
+udp_propinfo_tbl
+udp_propinfo_count
 udp_random_anon_port
 udp_rinitv4
 udp_rinitv6
--- a/usr/src/uts/intel/sctp/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the sctp driver kernel module.
-#
-#	intel implementation architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sctp
-OBJECTS		= $(SCTP_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(SCTP_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/inet/sctp
-
-#
-# Extra for $(MODULE).check target
-#
-# Need to remove ipddi.o since it has non-static defines for _init etc.
-IP_CHECK_OBJS	= $(IP_OBJS:ipddi.o=ip.o)
-EXTRA_CHECK_OBJS = $(IP_CHECK_OBJS:%=../ip/$(OBJS_DIR)/%)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
-
-#
-#	depends on ip
-#
-LDFLAGS		+= -dy -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/sctp6/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the sctp6 driver kernel module.
-#
-#	intel implementation architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sctp6
-OBJECTS		= $(SCTP6_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(SCTP6_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/inet/sctp
-
-#
-# Extra for $(MODULE).check target
-#
-# Need to remove ipddi.o since it has non-static defines for _init etc.
-IP_CHECK_OBJS	= $(IP_OBJS:ipddi.o=ip.o)
-EXTRA_CHECK_OBJS = $(IP_CHECK_OBJS:%=../ip/$(OBJS_DIR)/%)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
-
-#
-#	depends on sctp ip
-#
-LDFLAGS		+= -dy -Ndrv/sctp -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Fri Mar 26 17:53:11 2010 -0400
@@ -212,7 +212,7 @@
 DRV_KMODS	+= simnet softmac sppp sppptun sy sysevent sysmsg 
 DRV_KMODS	+= spdsock
 DRV_KMODS	+= tcp tcp6 tl tnf ttymux udp udp6 wc winlock zcons
-DRV_KMODS	+= ippctl sctp sctp6
+DRV_KMODS	+= ippctl
 DRV_KMODS	+= dld
 DRV_KMODS	+= ipf
 DRV_KMODS	+= rpcib
--- a/usr/src/uts/sparc/ip/ip.global-objs.debug64	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/sparc/ip/ip.global-objs.debug64	Fri Mar 26 17:53:11 2010 -0400
@@ -76,7 +76,7 @@
 icmp_mod_info
 icmp_opt_arr
 icmp_opt_obj
-icmp_param_arr
+icmp_propinfo_tbl
 icmp_valid_levels_arr
 icmpinfov4
 icmpinfov6
@@ -128,6 +128,8 @@
 ip_ndx_ioctl_table
 ip_poll_normal_ms
 ip_poll_normal_ticks
+ip_propinfo_tbl
+ip_propinfo_count
 ip_rput_pullups
 ip_six_byte_all_ones
 ip_squeue_create_callback
@@ -161,14 +163,12 @@
 ipsec_sel_cache
 ipsec_spd_hashsize
 ipsec_weird_null_inbound_policy
-ipv4_forward_suffix
 ipv4info
 ipv6_all_hosts_mcast
 ipv6_all_ones
 ipv6_all_rtrs_mcast
 ipv6_all_v2rtrs_mcast
 ipv6_all_zeros
-ipv6_forward_suffix
 ipv6_ll_template
 ipv6_loopback
 ipv6_solicited_node_mcast
@@ -180,12 +180,7 @@
 ire_null
 ire_nv_arr
 ire_nv_tbl
-lcl_ndp_arr
 lcl_param_arr
-lcl_sctp_param_arr
-lcl_sctp_wroff_xtra_param
-lcl_tcp_param_arr
-lcl_tcp_wroff_xtra_param
 mask_rnhead
 max_keylen
 modldrv
@@ -224,18 +219,16 @@
 sctp_kmem_faddr_cache
 sctp_kmem_ftsn_set_cache
 sctp_kmem_set_cache
-sctp_mod_info
 sctp_opt_arr
 sctp_opt_arr_size
+sctp_propinfo_tbl
+sctp_propinfo_count
 sctp_recvq_tq_task_max
 sctp_recvq_tq_task_min
 sctp_recvq_tq_thr_max
 sctp_recvq_tq_thr_min
 sctp_sin6_null
 sctpdebug
-sctpinfo
-sctprinit
-sctpwinit
 sin6_null
 sin_null
 skip_sctp_cksum
@@ -272,6 +265,8 @@
 tcp_opt_arr
 tcp_opt_obj
 tcp_outbound_squeue_switch
+tcp_propinfo_tbl
+tcp_propinfo_count
 tcp_random_anon_port
 tcp_random_end_ptr
 tcp_random_fptr
@@ -308,7 +303,8 @@
 udp_mod_info
 udp_opt_arr
 udp_opt_obj
-udp_param_arr
+udp_propinfo_tbl
+udp_propinfo_count
 udp_random_anon_port
 udp_rinitv4
 udp_rinitv6
--- a/usr/src/uts/sparc/ip/ip.global-objs.obj64	Fri Mar 26 14:31:08 2010 -0700
+++ b/usr/src/uts/sparc/ip/ip.global-objs.obj64	Fri Mar 26 17:53:11 2010 -0400
@@ -76,7 +76,7 @@
 icmp_mod_info
 icmp_opt_arr
 icmp_opt_obj
-icmp_param_arr
+icmp_propinfo_tbl
 icmp_valid_levels_arr
 icmpinfov4
 icmpinfov6
@@ -128,6 +128,8 @@
 ip_ndx_ioctl_table
 ip_poll_normal_ms
 ip_poll_normal_ticks
+ip_propinfo_tbl
+ip_propinfo_count
 ip_rput_pullups
 ip_six_byte_all_ones
 ip_squeue_create_callback
@@ -161,14 +163,12 @@
 ipsec_sel_cache
 ipsec_spd_hashsize
 ipsec_weird_null_inbound_policy
-ipv4_forward_suffix
 ipv4info
 ipv6_all_hosts_mcast
 ipv6_all_ones
 ipv6_all_rtrs_mcast
 ipv6_all_v2rtrs_mcast
 ipv6_all_zeros
-ipv6_forward_suffix
 ipv6_ll_template
 ipv6_loopback
 ipv6_solicited_node_mcast
@@ -180,12 +180,7 @@
 ire_null
 ire_nv_arr
 ire_nv_tbl
-lcl_ndp_arr
 lcl_param_arr
-lcl_sctp_param_arr
-lcl_sctp_wroff_xtra_param
-lcl_tcp_param_arr
-lcl_tcp_wroff_xtra_param
 mask_rnhead
 max_keylen
 modldrv
@@ -222,18 +217,16 @@
 sctp_kmem_faddr_cache
 sctp_kmem_ftsn_set_cache
 sctp_kmem_set_cache
-sctp_mod_info
 sctp_opt_arr
 sctp_opt_arr_size
+sctp_propinfo_tbl
+sctp_propinfo_count
 sctp_recvq_tq_task_max
 sctp_recvq_tq_task_min
 sctp_recvq_tq_thr_max
 sctp_recvq_tq_thr_min
 sctp_sin6_null
 sctpdebug
-sctpinfo
-sctprinit
-sctpwinit
 sin6_null
 sin_null
 sock_rawip_downcalls
@@ -269,6 +262,8 @@
 tcp_opt_arr
 tcp_opt_obj
 tcp_outbound_squeue_switch
+tcp_propinfo_tbl
+tcp_propinfo_count
 tcp_random_anon_port
 tcp_random_end_ptr
 tcp_random_fptr
@@ -305,7 +300,8 @@
 udp_mod_info
 udp_opt_arr
 udp_opt_obj
-udp_param_arr
+udp_propinfo_tbl
+udp_propinfo_count
 udp_random_anon_port
 udp_rinitv4
 udp_rinitv6
--- a/usr/src/uts/sparc/sctp/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the sctp driver kernel module.
-#
-#	sparc architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sctp
-OBJECTS		= $(SCTP_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(SCTP_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/inet/sctp
-
-#
-# Extra for $(MODULE).check target
-#
-# Need to remove ipddi.o since it has non-static defines for _init etc.
-IP_CHECK_OBJS	= $(IP_OBJS:ipddi.o=ip.o)
-EXTRA_CHECK_OBJS = $(IP_CHECK_OBJS:%=../ip/$(OBJS_DIR)/%)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
-
-#
-# lint pass one enforcement
-#
-CFLAGS		+= -v
-
-#
-#	depends on IP
-#
-LDFLAGS		+= -dy -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ
--- a/usr/src/uts/sparc/sctp6/Makefile	Fri Mar 26 14:31:08 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (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]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-#	This makefile drives the production of the sctp6 driver kernel module.
-#
-#	sparc architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sctp6
-OBJECTS		= $(SCTP6_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(SCTP6_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-CONF_SRCDIR	= $(UTSBASE)/common/inet/sctp
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY) $(SRC_CONFFILE)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
-
-#
-# lint pass one enforcement
-#
-CFLAGS		+= -v
-LDFLAGS		+= -dy -Ndrv/sctp -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ