summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGirish Moodalbail <Girish.Moodalbail@Sun.COM>2010-03-26 17:53:11 -0400
committerGirish Moodalbail <Girish.Moodalbail@Sun.COM>2010-03-26 17:53:11 -0400
commit6e91bba0d6c6bdabbba62cefae583715a4a58e2a (patch)
treee10bc428e6a27ac87b541b72769d8095d64e894f /usr/src
parent00a57bdfe7eeb62d10d0c0b3aab64d24a4d89287 (diff)
downloadillumos-gate-6e91bba0d6c6bdabbba62cefae583715a4a58e2a.tar.gz
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
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/Targetdirs1
-rw-r--r--usr/src/cmd/cmd-inet/lib/Makefile10
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile90
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf26
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c845
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h152
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c382
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c1136
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c (renamed from usr/src/uts/common/inet/sctp/sctpddi.c)50
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt62
-rw-r--r--usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml95
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile14
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h6
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c479
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c107
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c104
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h16
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/Makefile7
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile4
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c1148
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h5
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile94
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c2198
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl137
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/ndd.c311
-rw-r--r--usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding31
-rw-r--r--usr/src/cmd/rcm_daemon/Makefile.com4
-rw-r--r--usr/src/cmd/rcm_daemon/common/ip_rcm.c266
-rw-r--r--usr/src/cmd/svc/milestone/net-iptun23
-rw-r--r--usr/src/cmd/svc/milestone/net-loopback52
-rw-r--r--usr/src/cmd/svc/milestone/net-physical25
-rw-r--r--usr/src/cmd/svc/seed/Makefile3
-rw-r--r--usr/src/cmd/truss/codes.c2
-rw-r--r--usr/src/head/Makefile3
-rw-r--r--usr/src/head/ifaddrs.h89
-rw-r--r--usr/src/lib/Makefile14
-rw-r--r--usr/src/lib/brand/solaris10/zone/s10_boot.ksh9
-rw-r--r--usr/src/lib/libbc/inc/include/net/if.h24
-rw-r--r--usr/src/lib/libinetcfg/common/inetcfg.c52
-rw-r--r--usr/src/lib/libinetutil/common/inetutil.c102
-rw-r--r--usr/src/lib/libinetutil/common/libinetutil.h14
-rw-r--r--usr/src/lib/libinetutil/common/mapfile-vers7
-rw-r--r--usr/src/lib/libipadm/Makefile61
-rw-r--r--usr/src/lib/libipadm/Makefile.com53
-rw-r--r--usr/src/lib/libipadm/common/ipadm_addr.c3466
-rw-r--r--usr/src/lib/libipadm/common/ipadm_if.c1534
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ipmgmt.h272
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ndpd.c366
-rw-r--r--usr/src/lib/libipadm/common/ipadm_ndpd.h72
-rw-r--r--usr/src/lib/libipadm/common/ipadm_persist.c828
-rw-r--r--usr/src/lib/libipadm/common/ipadm_prop.c1699
-rw-r--r--usr/src/lib/libipadm/common/libipadm.c922
-rw-r--r--usr/src/lib/libipadm/common/libipadm.h346
-rw-r--r--usr/src/lib/libipadm/common/libipadm_impl.h227
-rw-r--r--usr/src/lib/libipadm/common/llib-lipadm35
-rw-r--r--usr/src/lib/libipadm/common/mapfile-vers93
-rw-r--r--usr/src/lib/libipadm/i386/Makefile (renamed from usr/src/uts/common/inet/sctp/sctp.conf)14
-rw-r--r--usr/src/lib/libipadm/libipadm.xcl89
-rw-r--r--usr/src/lib/libipadm/sparc/Makefile (renamed from usr/src/uts/common/inet/sctp/sctp6.conf)13
-rw-r--r--usr/src/lib/libsecdb/auth_attr.txt1
-rw-r--r--usr/src/lib/libsecdb/exec_attr.txt2
-rw-r--r--usr/src/lib/libsecdb/help/auths/Makefile1
-rw-r--r--usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html42
-rw-r--r--usr/src/lib/libsecdb/prof_attr.txt2
-rw-r--r--usr/src/lib/libsocket/Makefile12
-rw-r--r--usr/src/lib/libsocket/Makefile.com5
-rw-r--r--usr/src/lib/libsocket/common/libsocket_priv.h (renamed from usr/src/uts/common/inet/sctp/sctp6ddi.c)47
-rw-r--r--usr/src/lib/libsocket/common/llib-lsocket11
-rw-r--r--usr/src/lib/libsocket/common/mapfile-vers10
-rw-r--r--usr/src/lib/libsocket/inet/getifaddrs.c269
-rw-r--r--usr/src/pkg/manifests/SUNWcs.mf5
-rw-r--r--usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf1
-rw-r--r--usr/src/pkg/manifests/system-header.mf2
-rw-r--r--usr/src/pkg/manifests/system-kernel.mf8
-rw-r--r--usr/src/pkg/manifests/system-library.mf1
-rw-r--r--usr/src/pkg/manifests/system-network.mf3
-rw-r--r--usr/src/tools/scripts/bfu.sh19
-rw-r--r--usr/src/uts/common/Makefile.files21
-rw-r--r--usr/src/uts/common/inet/Makefile2
-rw-r--r--usr/src/uts/common/inet/ip.h184
-rw-r--r--usr/src/uts/common/inet/ip/icmp.c171
-rw-r--r--usr/src/uts/common/inet/ip/igmp.c3
-rw-r--r--usr/src/uts/common/inet/ip/ip.c549
-rw-r--r--usr/src/uts/common/inet/ip/ip6_if.c9
-rw-r--r--usr/src/uts/common/inet/ip/ip6_ire.c1
-rw-r--r--usr/src/uts/common/inet/ip/ip_if.c565
-rw-r--r--usr/src/uts/common/inet/ip/ip_ire.c1
-rw-r--r--usr/src/uts/common/inet/ip/ip_mroute.c11
-rw-r--r--usr/src/uts/common/inet/ip/ip_rts.c5
-rw-r--r--usr/src/uts/common/inet/ip/ip_tunables.c820
-rw-r--r--usr/src/uts/common/inet/ip_if.h11
-rw-r--r--usr/src/uts/common/inet/ip_impl.h6
-rw-r--r--usr/src/uts/common/inet/ip_stack.h25
-rw-r--r--usr/src/uts/common/inet/nd.c25
-rw-r--r--usr/src/uts/common/inet/rawip_impl.h14
-rw-r--r--usr/src/uts/common/inet/sctp/sctp.c25
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_impl.h139
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_ioc.c272
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_param.c361
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_stack.h10
-rw-r--r--usr/src/uts/common/inet/sctp/sctp_tunables.c218
-rw-r--r--usr/src/uts/common/inet/sctp_ip.h3
-rw-r--r--usr/src/uts/common/inet/tcp/tcp.c387
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_misc.c96
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_output.c12
-rw-r--r--usr/src/uts/common/inet/tcp/tcp_tunables.c480
-rw-r--r--usr/src/uts/common/inet/tcp_impl.h155
-rw-r--r--usr/src/uts/common/inet/tcp_stack.h8
-rw-r--r--usr/src/uts/common/inet/tunables.c444
-rw-r--r--usr/src/uts/common/inet/tunables.h163
-rw-r--r--usr/src/uts/common/inet/udp/udp.c233
-rw-r--r--usr/src/uts/common/inet/udp/udp_tunables.c104
-rw-r--r--usr/src/uts/common/inet/udp_impl.h49
-rw-r--r--usr/src/uts/common/io/strplumb.c7
-rw-r--r--usr/src/uts/common/net/if.h15
-rw-r--r--usr/src/uts/common/sys/sockio.h21
-rw-r--r--usr/src/uts/intel/Makefile.intel.shared2
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.debug6422
-rw-r--r--usr/src/uts/intel/ip/ip.global-objs.obj6422
-rw-r--r--usr/src/uts/intel/sctp/Makefile95
-rw-r--r--usr/src/uts/intel/sctp6/Makefile95
-rw-r--r--usr/src/uts/sparc/Makefile.sparc.shared2
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.debug6422
-rw-r--r--usr/src/uts/sparc/ip/ip.global-objs.obj6422
-rw-r--r--usr/src/uts/sparc/sctp/Makefile100
-rw-r--r--usr/src/uts/sparc/sctp6/Makefile89
127 files changed, 20717 insertions, 4110 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 2182a61ff9..baaf43922c 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -376,6 +376,7 @@ COMMON_SUBDIRS = \
lib/libinetsvc \
lib/libinetutil \
lib/libinstzones \
+ lib/libipadm \
lib/libipmi \
lib/libipmp \
lib/libipp \
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index ce20527857..a4131e292e 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -118,6 +118,7 @@ DIRS= \
/etc/hal/fdi/preprobe/10osvendor \
/etc/hal/fdi/preprobe/20thirdparty \
/etc/hal/fdi/preprobe/30user \
+ /etc/ipadm \
/etc/iscsi \
/etc/rpcsec \
/etc/security \
diff --git a/usr/src/cmd/cmd-inet/lib/Makefile b/usr/src/cmd/cmd-inet/lib/Makefile
index f497fc41b5..0c527437e0 100644
--- a/usr/src/cmd/cmd-inet/lib/Makefile
+++ b/usr/src/cmd/cmd-inet/lib/Makefile
@@ -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 @@ $(SUBDIRS): FRC
FRC:
-include ../Makefile.msg
+include ../Makefile.msg
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
new file mode 100644
index 0000000000..344fb9e6fc
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/Makefile
@@ -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
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf
new file mode 100644
index 0000000000..eeaee090b6
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipadm.conf
@@ -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.
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
new file mode 100644
index 0000000000..d2996faf53
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_door.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
new file mode 100644
index 0000000000..7ed45205a3
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_impl.h
@@ -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 */
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
new file mode 100644
index 0000000000..011126d010
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_main.c
@@ -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);
+}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
new file mode 100644
index 0000000000..deb077036d
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c
@@ -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);
+}
diff --git a/usr/src/uts/common/inet/sctp/sctpddi.c b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c
index 16b8551712..8ef9a09e3d 100644
--- a/usr/src/uts/common/inet/sctp/sctpddi.c
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_util.c
@@ -18,45 +18,29 @@
*
* 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.
*/
-#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"
+/*
+ * Utility functions used by the ipmgmtd daemon.
+ */
-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));
-}
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include "ipmgmt_impl.h"
-int
-_fini(void)
+void
+ipmgmt_log(int pri, const char *fmt, ...)
{
- return (mod_remove(&modlinkage));
-}
+ va_list alist;
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&modlinkage, modinfop));
+ va_start(alist, fmt);
+ vsyslog(pri, fmt, alist);
+ va_end(alist);
}
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt b/usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt
new file mode 100644
index 0000000000..e88c9a5352
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/net-ipmgmt
@@ -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
diff --git a/usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml b/usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml
new file mode 100644
index 0000000000..7f2c7f53be
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/lib/ipmgmtd/network-ipmgmt.xml
@@ -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>
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile
index 3aca7d0fd9..542c79feb0 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/Makefile
@@ -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 @@ ROOTMANIFESTDIR= $(ROOTSVCNETWORKROUTING)
# 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 @@ LINTFLAGS += -erroff=E_INCONS_ARG_DECL2 -erroff=E_INCONS_VAL_TYPE_DECL2
# 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 @@ LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
all: $(PROG)
$(PROG): $(OBJS)
- $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(CTFMERGE_HOOK)
$(POST_PROCESS)
include ../Makefile.lib
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h
index 54c6fb6e35..169cdb6014 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/defs.h
@@ -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"
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
index df8c79478e..62ba4df299 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
@@ -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 @@ int rtsock = -1; /* Routing socket */
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 @@ poll_add(int fd)
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 @@ if_process(int s, char *ifname, boolean_t first)
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 @@ solicit_event(struct phyint *pi, enum solicit_events event, uint_t elapsed)
"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 @@ in_signal(int fd)
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 @@ in_signal(int fd)
/* 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 @@ check_if_removed(struct phyint *pi)
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 @@ check_if_removed(struct phyint *pi)
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 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
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 @@ logperror_pr(const struct prefix *pr, const char *str)
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);
+}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c
index 0a9e1e6a13..5f1acb2301 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c
@@ -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 @@ incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len,
}
/*
- * 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.
*/
-void
-start_dhcp(struct phyint *pi)
+int
+dhcp_op(struct phyint *pi, int type)
{
dhcp_ipc_request_t *request;
dhcp_ipc_reply_t *reply = NULL;
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);
- /* 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");
+ logmsg(LOG_ERR, "dhcp_op: 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;
+ 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, "start_dhcp: err: %s: %s\n", pi->pi_name,
- dhcp_ipc_strerror(error));
- return;
+ 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)
+{
+ int error;
+ int type;
+
+ if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
+ 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;
+ }
+
+ else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED)
+ type = DHCP_START;
+ else
+ type = DHCP_INFORM;
+
+ 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 @@ incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len,
* 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 @@ incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
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 @@ incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
"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 @@ incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
/*
* 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 @@ incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
"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);
}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c
index 09e6137965..72c006b63a 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.c
@@ -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 @@ phyint_create(char *name)
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 @@ start_over:
(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 @@ start_over:
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;
- }
- /* 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;
+ 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;
}
- 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 @@ phyint_delete(struct phyint *pi)
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 @@ prefix_init_from_k(struct prefix *pr)
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 @@ error:
* 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 @@ prefix_delete(struct prefix *pr)
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 @@ prefix_delete(struct prefix *pr)
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 @@ prefix_update_k(struct prefix *pr)
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 @@ phyint_cleanup(struct phyint *pi)
(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);
}
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h
index dfc5414d5d..5024c3d57b 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/tables.h
@@ -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 @@ extern "C" {
#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 @@ struct phyint {
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 @@ struct phyint {
* 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 print_prefixlist(struct confvar *confvar);
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 boolean_t incoming_prefix_addrconf_process(struct phyint *pi,
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
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
index ce1ffcf27e..f7ae749660 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile
@@ -54,7 +54,7 @@ NSLPROG= 6to4relay arp gettable hostconfig in.comsat in.rarpd \
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 @@ K5TELNETOBJS= in.telnetd.o
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 @@ in.rarpd := LDLIBS += -linetutil -ldlpi
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:
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
index 64fe8e8ae7..9144fb1439 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/Makefile
@@ -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 @@ COMMONSRCS= $(CMDINETCOMMONDIR)/$(COMMONOBJS:%.o=%.c)
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)/%)
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
index 85e95c5fa4..ba798ccfcd 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.c
@@ -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 @@ static char name[LIFNAMSIZ];
/* 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 setifgroupname(char *arg, int64_t param);
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 setzone(char *arg, int64_t param);
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 @@ static void in6_configinfo(int force, uint64_t flags);
* 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 @@ main(int argc, char *argv[])
{
int64_t lifc_flags;
char *default_ip_str;
+ ipadm_status_t istatus;
- lifc_flags = LIFC_NOXMIT|LIFC_TEMPORARY|LIFC_ALLZONES|LIFC_UNDER_IPMP;
+ lifc_flags = LIFC_DEFAULT;
if (argc < 2) {
usage();
@@ -412,6 +422,13 @@ main(int argc, char *argv[])
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 @@ main(int argc, char *argv[])
"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;
+ ipadm_addr_info_t *ainfo, *ainfop;
+ struct ifaddrs *ifa;
+ ipadm_status_t istatus;
- buf = NULL;
/*
* 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");
- }
- 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;
- }
+ 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");
- 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.
- */
+ /*
+ * 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) {
- (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)
+ if ((ifa->ifa_flags & onflags) != onflags)
continue;
- if ((~lifrl.lifr_flags & offflags) != offflags)
+ if ((~ifa->ifa_flags & offflags) != offflags)
continue;
}
+ 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);
+}
- 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);
+/*
+ * 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;
- 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");
- }
- }
- }
+ 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++) {
/*
* Reset global state
* setaddr: Used by parser to tear apart source and dest
@@ -644,24 +593,23 @@ foreachinterface(void (*func)(), int argc, char *argv[], int af,
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 @@ ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
* 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 @@ ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
* 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 @@ ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp)
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 @@ set_mask_lifreq(struct lifreq *lifr, struct sockaddr_storage *addr,
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 @@ setifaddr(char *addr, int64_t param)
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 @@ setifaddr(char *addr, int64_t param)
* 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 @@ setifether(char *addr, int64_t param)
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 @@ setifether(char *addr, int64_t param)
* 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 @@ addif(char *str, int64_t param)
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 @@ addif(char *str, int64_t param)
* 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 @@ static int
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 @@ removeif(char *str, int64_t param)
}
(*afp->af_getaddr)(str, &laddr, NULL);
- lifr.lifr_addr = laddr;
+ /*
+ * 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 @@ modremove(char *arg, int64_t param)
}
/*
- * 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 @@ ip_domux2fd(int *muxfd, int *muxid_fd, int *ipfd_lowstr, int *arpfd_lowstr,
/*
* 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 @@ setifsrc(char *arg, int64_t param)
* 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 @@ ifstatus(const char *ifname)
(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 @@ status(void)
(*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 @@ in6_configinfo(int force, uint64_t flags)
}
/*
- * 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 @@ out:
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");
- }
- 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);
- }
+ ipadm_status_t istatus;
- 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");
- }
- }
+ 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);
}
- 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;
+ ipadm_status_t istatus;
- 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);
- }
-
- /*
- * 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);
- }
+ 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 (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 @@ inetipmp(char *arg, int64_t param)
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 @@ create_ipmp(const char *grname, int af, const char *ifname, boolean_t implicit)
}
/*
- * 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 @@ ifconfig_dladm_open(const char *name, datalink_class_t reqclass,
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 @@ lifnum(const char *ifname)
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)
{
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h
index f11f4d0a94..85f9ec0b17 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ifconfig/ifconfig.h
@@ -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 @@ extern "C" {
#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 *);
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile
new file mode 100644
index 0000000000..94b41cfaaa
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile
@@ -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
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
new file mode 100644
index 0000000000..75833cf5b5
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.c
@@ -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);
+ }
+}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl
new file mode 100644
index 0000000000..cf59500dc1
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/ipadm.xcl
@@ -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"
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ndd.c b/usr/src/cmd/cmd-inet/usr.sbin/ndd.c
index 23b0ae9e20..e45ecc12ea 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/ndd.c
+++ b/usr/src/cmd/cmd-inet/usr.sbin/ndd.c
@@ -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 char *errmsg(int err);
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 @@ gldv3_warning(char *module)
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 @@ main(int argc, char **argv)
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 @@ do_getset(int fd, int cmd, char *buf, int buf_len)
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 @@ printe(boolean_t print_errno, char *fmt, ...)
(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);
}
}
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
index db3ead4bf7..48f77f98e1 100644
--- a/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
+++ b/usr/src/cmd/cmd-inet/usr.sbin/routeadm/svc-forwarding
@@ -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 @@ case "$1" in
#
# 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
diff --git a/usr/src/cmd/rcm_daemon/Makefile.com b/usr/src/cmd/rcm_daemon/Makefile.com
index d5a7c72ff7..f053428473 100644
--- a/usr/src/cmd/rcm_daemon/Makefile.com
+++ b/usr/src/cmd/rcm_daemon/Makefile.com
@@ -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_network_rcm.so := LDLIBS_MODULES += -L$(ROOT)/lib -ldladm
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
diff --git a/usr/src/cmd/rcm_daemon/common/ip_rcm.c b/usr/src/cmd/rcm_daemon/common/ip_rcm.c
index 84c195f349..2ab9959372 100644
--- a/usr/src/cmd/rcm_daemon/common/ip_rcm.c
+++ b/usr/src/cmd/rcm_daemon/common/ip_rcm.c
@@ -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 mutex_t cache_lock;
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 ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
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 @@ static void ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
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 @@ rcm_mod_init(void)
{
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 @@ rcm_mod_init(void)
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 @@ rcm_mod_fini(void)
(void) mutex_destroy(&cache_lock);
dladm_close(dld_handle);
+ ipadm_close(ip_handle);
return (RCM_SUCCESS);
}
@@ -758,7 +773,25 @@ ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
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 @@ cache_remove(ip_cache_t *node)
* 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 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
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 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
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 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
}
/* 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 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
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 @@ update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
static int
update_ipifs(rcm_handle_t *hd, int af)
{
- int sock;
- char *buf;
- struct lifnum lifn;
- struct lifconf lifc;
- struct lifreq *lifrp;
- int i;
- rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
+ struct ifaddrs *ifa;
+ ipadm_addr_info_t *ainfo;
+ ipadm_addr_info_t *ptr;
+ ipadm_status_t status;
+ int sock;
if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
rcm_log_message(RCM_ERROR,
@@ -1236,46 +1252,20 @@ update_ipifs(rcm_handle_t *hd, int af)
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));
- (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);
+ status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
+ LIFC_UNDER_IPMP);
+ if (status != IPADM_SUCCESS) {
(void) close(sock);
return (-1);
}
-
- /* 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++;
+ 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);
}
-
- free(buf);
(void) close(sock);
+ ipadm_free_addr_info(ainfo);
return (0);
}
@@ -2270,20 +2260,15 @@ ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
}
/*
- * 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 @@ if_configure(datalink_id_t linkid)
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 @@ if_configure(datalink_id_t linkid)
(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 @@ fail:
}
/*
+ * 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 @@ ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
}
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);
+}
diff --git a/usr/src/cmd/svc/milestone/net-iptun b/usr/src/cmd/svc/milestone/net-iptun
index 778f76b1f7..f912d6ee9a 100644
--- a/usr/src/cmd/svc/milestone/net-iptun
+++ b/usr/src/cmd/svc/milestone/net-iptun
@@ -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 @@ start)
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 @@ stop)
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
diff --git a/usr/src/cmd/svc/milestone/net-loopback b/usr/src/cmd/svc/milestone/net-loopback
index d07afd4ada..bd52bbc719 100644
--- a/usr/src/cmd/svc/milestone/net-loopback
+++ b/usr/src/cmd/svc/milestone/net-loopback
@@ -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
+ # 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
-# IPv6 loopback
-/sbin/ifconfig lo0 inet6 plumb ::1 up
+ # 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/ifconfig lo0 all-zones
- /sbin/ifconfig lo0 inet6 all-zones
+ # 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
+
diff --git a/usr/src/cmd/svc/milestone/net-physical b/usr/src/cmd/svc/milestone/net-physical
index 63e4264204..2a5b7d7515 100644
--- a/usr/src/cmd/svc/milestone/net-physical
+++ b/usr/src/cmd/svc/milestone/net-physical
@@ -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 @@ is_iptun ()
#
#
+# 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 @@ if [ -n "$ipmp6_list" ]; then
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.
#
diff --git a/usr/src/cmd/svc/seed/Makefile b/usr/src/cmd/svc/seed/Makefile
index 7e69e27a54..1fffd9d283 100644
--- a/usr/src/cmd/svc/seed/Makefile
+++ b/usr/src/cmd/svc/seed/Makefile
@@ -67,7 +67,8 @@ COMMON_DESCRIPTIONS = \
../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
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index 0bec448ea6..03f7b40ab0 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -879,6 +879,8 @@ const struct ioc {
{ (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" },
diff --git a/usr/src/head/Makefile b/usr/src/head/Makefile
index c2e0c2f0e8..2a51b192ed 100644
--- a/usr/src/head/Makefile
+++ b/usr/src/head/Makefile
@@ -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 @@ HDRS= $($(MACH)_HDRS) $(ATTRDB_HDRS) \
grp.h \
iconv.h \
ieeefp.h \
+ ifaddrs.h \
inttypes.h \
iso646.h \
klpd.h \
diff --git a/usr/src/head/ifaddrs.h b/usr/src/head/ifaddrs.h
new file mode 100644
index 0000000000..f29aee16e9
--- /dev/null
+++ b/usr/src/head/ifaddrs.h
@@ -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 */
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 4086c4210c..2ed5c76543 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -112,6 +112,7 @@ SUBDIRS += \
libcryptoutil \
libinetcfg \
libinetutil \
+ libipadm \
libipmp \
libiscsit \
libkmf \
@@ -334,6 +335,7 @@ MSGSUBDIRS= \
libilb \
libinetutil \
libinstzones \
+ libipadm \
libnsl \
libnwam \
libpam \
@@ -386,6 +388,7 @@ HDRSUBDIRS= \
libc \
libcmd \
libcmdutils \
+ libcommputil \
libcontract \
libcpc \
libctf \
@@ -411,8 +414,7 @@ HDRSUBDIRS= \
libfru \
libfstyp \
libgen \
- libwanboot \
- libwanbootutil \
+ libipadm \
libipsecutil \
libinetcfg \
libinetsvc \
@@ -445,7 +447,6 @@ HDRSUBDIRS= \
librdc \
libscf \
libsip \
- libcommputil \
libsmbios \
librestart \
librpcsvc \
@@ -456,6 +457,7 @@ HDRSUBDIRS= \
libshell \
libslp \
libsmedia \
+ libsocket \
libsqlite \
libfcoe \
libstmf \
@@ -473,6 +475,8 @@ HDRSUBDIRS= \
libumem \
libunistat \
libuutil \
+ libwanboot \
+ libwanbootutil \
libwrap \
libxcurses2 \
libzfs \
@@ -592,7 +596,9 @@ libefi: libuuid
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
diff --git a/usr/src/lib/brand/solaris10/zone/s10_boot.ksh b/usr/src/lib/brand/solaris10/zone/s10_boot.ksh
index 09c4f39a59..5a57696eef 100644
--- a/usr/src/lib/brand/solaris10/zone/s10_boot.ksh
+++ b/usr/src/lib/brand/solaris10/zone/s10_boot.ksh
@@ -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 @@ safe_dir /sbin
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
diff --git a/usr/src/lib/libbc/inc/include/net/if.h b/usr/src/lib/libbc/inc/include/net/if.h
index 389bb290b6..513fa0d2bf 100644
--- a/usr/src/lib/libbc/inc/include/net/if.h
+++ b/usr/src/lib/libbc/inc/include/net/if.h
@@ -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 @@ struct ifnet {
#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 @@ struct ifnet {
* 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 ifaddr {
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 ifreq {
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 @@ struct ifreq {
#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
};
diff --git a/usr/src/lib/libinetcfg/common/inetcfg.c b/usr/src/lib/libinetcfg/common/inetcfg.c
index cdcbf00329..f61df0e287 100644
--- a/usr/src/lib/libinetcfg/common/inetcfg.c
+++ b/usr/src/lib/libinetcfg/common/inetcfg.c
@@ -128,32 +128,6 @@ dlpi_error_to_icfg_error(int err)
}
/*
- * 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 @@ icfg_set_prefixlen(icfg_handle_t handle, int prefixlen)
{
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);
}
diff --git a/usr/src/lib/libinetutil/common/inetutil.c b/usr/src/lib/libinetutil/common/inetutil.c
index 195d080b79..be92c0e77d 100644
--- a/usr/src/lib/libinetutil/common/inetutil.c
+++ b/usr/src/lib/libinetutil/common/inetutil.c
@@ -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 @@ sockaddrcmp(const struct sockaddr_storage *ssp1,
}
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);
+}
diff --git a/usr/src/lib/libinetutil/common/libinetutil.h b/usr/src/lib/libinetutil/common/libinetutil.h
index a285103af6..d294e6b50c 100644
--- a/usr/src/lib/libinetutil/common/libinetutil.h
+++ b/usr/src/lib/libinetutil/common/libinetutil.h
@@ -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 @@ typedef struct {
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:
diff --git a/usr/src/lib/libinetutil/common/mapfile-vers b/usr/src/lib/libinetutil/common/mapfile-vers
index 8bc79dd4cb..8dc7fb2c3a 100644
--- a/usr/src/lib/libinetutil/common/mapfile-vers
+++ b/usr/src/lib/libinetutil/common/mapfile-vers
@@ -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 @@ SUNWprivate_1.1 {
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:
*;
};
diff --git a/usr/src/lib/libipadm/Makefile b/usr/src/lib/libipadm/Makefile
new file mode 100644
index 0000000000..4e407d7fc4
--- /dev/null
+++ b/usr/src/lib/libipadm/Makefile
@@ -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
diff --git a/usr/src/lib/libipadm/Makefile.com b/usr/src/lib/libipadm/Makefile.com
new file mode 100644
index 0000000000..60f677736e
--- /dev/null
+++ b/usr/src/lib/libipadm/Makefile.com
@@ -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
diff --git a/usr/src/lib/libipadm/common/ipadm_addr.c b/usr/src/lib/libipadm/common/ipadm_addr.c
new file mode 100644
index 0000000000..fb39cb1a24
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_addr.c
@@ -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));
+}
diff --git a/usr/src/lib/libipadm/common/ipadm_if.c b/usr/src/lib/libipadm/common/ipadm_if.c
new file mode 100644
index 0000000000..d4a24d49a4
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_if.c
@@ -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);
+ }
+}
diff --git a/usr/src/lib/libipadm/common/ipadm_ipmgmt.h b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
new file mode 100644
index 0000000000..7bd0d19f23
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_ipmgmt.h
@@ -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 */
diff --git a/usr/src/lib/libipadm/common/ipadm_ndpd.c b/usr/src/lib/libipadm/common/ipadm_ndpd.c
new file mode 100644
index 0000000000..2030295e24
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_ndpd.c
@@ -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);
+}
diff --git a/usr/src/lib/libipadm/common/ipadm_ndpd.h b/usr/src/lib/libipadm/common/ipadm_ndpd.h
new file mode 100644
index 0000000000..f35f8d9b7a
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_ndpd.h
@@ -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 */
diff --git a/usr/src/lib/libipadm/common/ipadm_persist.c b/usr/src/lib/libipadm/common/ipadm_persist.c
new file mode 100644
index 0000000000..698d4af359
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_persist.c
@@ -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);
+}
diff --git a/usr/src/lib/libipadm/common/ipadm_prop.c b/usr/src/lib/libipadm/common/ipadm_prop.c
new file mode 100644
index 0000000000..56aba6bb2d
--- /dev/null
+++ b/usr/src/lib/libipadm/common/ipadm_prop.c
@@ -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);
+}
diff --git a/usr/src/lib/libipadm/common/libipadm.c b/usr/src/lib/libipadm/common/libipadm.c
new file mode 100644
index 0000000000..2c18331a7b
--- /dev/null
+++ b/usr/src/lib/libipadm/common/libipadm.c
@@ -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);
+}
diff --git a/usr/src/lib/libipadm/common/libipadm.h b/usr/src/lib/libipadm/common/libipadm.h
new file mode 100644
index 0000000000..621c06b4e4
--- /dev/null
+++ b/usr/src/lib/libipadm/common/libipadm.h
@@ -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 */
diff --git a/usr/src/lib/libipadm/common/libipadm_impl.h b/usr/src/lib/libipadm/common/libipadm_impl.h
new file mode 100644
index 0000000000..6572bc64b7
--- /dev/null
+++ b/usr/src/lib/libipadm/common/libipadm_impl.h
@@ -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 */
diff --git a/usr/src/lib/libipadm/common/llib-lipadm b/usr/src/lib/libipadm/common/llib-lipadm
new file mode 100644
index 0000000000..4553567250
--- /dev/null
+++ b/usr/src/lib/libipadm/common/llib-lipadm
@@ -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>
diff --git a/usr/src/lib/libipadm/common/mapfile-vers b/usr/src/lib/libipadm/common/mapfile-vers
new file mode 100644
index 0000000000..9a48e57547
--- /dev/null
+++ b/usr/src/lib/libipadm/common/mapfile-vers
@@ -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:
+ *;
+};
diff --git a/usr/src/uts/common/inet/sctp/sctp.conf b/usr/src/lib/libipadm/i386/Makefile
index 7755efa251..4d9d4abd5b 100644
--- a/usr/src/uts/common/inet/sctp/sctp.conf
+++ b/usr/src/lib/libipadm/i386/Makefile
@@ -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.
@@ -19,10 +18,11 @@
#
# 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.
#
-#ident ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
-name="sctp" parent="pseudo" instance=0;
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libipadm/libipadm.xcl b/usr/src/lib/libipadm/libipadm.xcl
new file mode 100644
index 0000000000..d8877dd4ca
--- /dev/null
+++ b/usr/src/lib/libipadm/libipadm.xcl
@@ -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"
diff --git a/usr/src/uts/common/inet/sctp/sctp6.conf b/usr/src/lib/libipadm/sparc/Makefile
index 75151c0c63..8069eadad1 100644
--- a/usr/src/uts/common/inet/sctp/sctp6.conf
+++ b/usr/src/lib/libipadm/sparc/Makefile
@@ -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,9 +19,11 @@
# 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.
#
-#ident ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
-name="sctp6" parent="pseudo" instance=0;
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt
index 0a10c10a11..7d5ef346c6 100644
--- a/usr/src/lib/libsecdb/auth_attr.txt
+++ b/usr/src/lib/libsecdb/auth_attr.txt
@@ -97,6 +97,7 @@ solaris.network.autoconf.wlan:::Create Network Auto-Magic Config for Known WLANs
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
diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt
index db47b15bd0..b7cfde648e 100644
--- a/usr/src/lib/libsecdb/exec_attr.txt
+++ b/usr/src/lib/libsecdb/exec_attr.txt
@@ -175,6 +175,8 @@ Network Management:solaris:cmd:::/sbin/dlstat:euid=dladm;egid=sys;
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
diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile
index cb9361c94e..6b1bb7737b 100644
--- a/usr/src/lib/libsecdb/help/auths/Makefile
+++ b/usr/src/lib/libsecdb/help/auths/Makefile
@@ -129,6 +129,7 @@ HTMLENTS = \
NetworkILBenable.html \
NetworkHeader.html \
NetworkVRRP.html \
+ NetworkInterfaceConfig.html \
WifiConfig.html \
WifiWep.html \
LinkSecurity.html \
diff --git a/usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html b/usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html
new file mode 100644
index 0000000000..afc2f5ebd1
--- /dev/null
+++ b/usr/src/lib/libsecdb/help/auths/NetworkInterfaceConfig.html
@@ -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>
diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt
index a8d5fc56b6..a1b5961d09 100644
--- a/usr/src/lib/libsecdb/prof_attr.txt
+++ b/usr/src/lib/libsecdb/prof_attr.txt
@@ -65,7 +65,7 @@ Network Autoconf Admin:::Manage Network Auto-Magic configuration via nwamd:profi
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
diff --git a/usr/src/lib/libsocket/Makefile b/usr/src/lib/libsocket/Makefile
index 18d1f13290..763363b7fd 100644
--- a/usr/src/lib/libsocket/Makefile
+++ b/usr/src/lib/libsocket/Makefile
@@ -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 @@ TEXT_DOMAIN = SUNW_OST_NETRPC
all clean clobber install lint: $(SUBDIRS)
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
_msg: $(MSGDOMAINPOFILE)
$(POFILE): pofile_MSGFILES
@@ -54,4 +57,5 @@ $(SUBDIRS): FRC
FRC:
+include $(SRC)/lib/Makefile.targ
include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/libsocket/Makefile.com b/usr/src/lib/libsocket/Makefile.com
index cdb99117c5..f1e7a0af99 100644
--- a/usr/src/lib/libsocket/Makefile.com
+++ b/usr/src/lib/libsocket/Makefile.com
@@ -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 @@ INETOBJS = bindresvport.o bootparams_getbyname.o ether_addr.o \
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)
diff --git a/usr/src/uts/common/inet/sctp/sctp6ddi.c b/usr/src/lib/libsocket/common/libsocket_priv.h
index db262a10ed..8d84ffb5da 100644
--- a/usr/src/uts/common/inet/sctp/sctp6ddi.c
+++ b/usr/src/lib/libsocket/common/libsocket_priv.h
@@ -19,44 +19,25 @@
* 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 _LIBSOCKET_PRIV_H
+#define _LIBSOCKET_PRIV_H
-#pragma ident "%Z%%M% %I% %E% SMI"
+#include <net/if.h>
+#include <ifaddrs.h>
-#include <sys/types.h>
-#include <sys/conf.h>
-#include <sys/modctl.h>
-#include <inet/common.h>
-#include <inet/ip.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
-#define INET_NAME "sctp6"
-#define INET_DEVDESC "SCTP6 device"
-#define INET_DEVSTRTAB sctpinfo
-#define INET_DEVMINOR 0
-#define INET_DEVMTFLAGS D_MP
+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 *);
-#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));
+#ifdef __cplusplus
}
+#endif
-int
-_info(struct modinfo *modinfop)
-{
- return (mod_info(&modlinkage, modinfop));
-}
+#endif /* _LIBSOCKET_PRIV_H */
diff --git a/usr/src/lib/libsocket/common/llib-lsocket b/usr/src/lib/libsocket/common/llib-lsocket
index f74c8cea92..104dc78235 100644
--- a/usr/src/lib/libsocket/common/llib-lsocket
+++ b/usr/src/lib/libsocket/common/llib-lsocket
@@ -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 @@ struct in6_addr *__inet6_rthdr_getaddr(void *, int);
/* 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);
diff --git a/usr/src/lib/libsocket/common/mapfile-vers b/usr/src/lib/libsocket/common/mapfile-vers
index 6839f8bb04..b71b64968d 100644
--- a/usr/src/lib/libsocket/common/mapfile-vers
+++ b/usr/src/lib/libsocket/common/mapfile-vers
@@ -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 @@ SUNWprivate_1.3 {
_nss_initf_netmasks;
_nss_initf_proto;
_nss_initf_services;
+ getallifaddrs;
+ getallifs;
str2ether;
str2addr;
str2netent;
diff --git a/usr/src/lib/libsocket/inet/getifaddrs.c b/usr/src/lib/libsocket/inet/getifaddrs.c
new file mode 100644
index 0000000000..893e83f730
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getifaddrs.c
@@ -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);
+}
diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf
index af8d0d9d59..5ccb4a0b87 100644
--- a/usr/src/pkg/manifests/SUNWcs.mf
+++ b/usr/src/pkg/manifests/SUNWcs.mf
@@ -486,6 +486,7 @@ file path=etc/user_attr.d/SUNWcs group=sys
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/ldap-client mode=0555
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/NetworkAutoconfWrite.html
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/manual-key.xml group=sys mode=0444
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/ifconfig target=../../sbin/ifconfig
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
diff --git a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
index fc19087040..de6c33c804 100644
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
@@ -137,6 +137,7 @@ file path=usr/lib/help/auths/locale/NetworkAutoconfWrite.html
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
diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf
index b95dd46026..915d16adc2 100644
--- a/usr/src/pkg/manifests/system-header.mf
+++ b/usr/src/pkg/manifests/system-header.mf
@@ -383,6 +383,7 @@ $(i386_ONLY)file path=usr/include/ia32/sys/traptrace.h
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.h
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
diff --git a/usr/src/pkg/manifests/system-kernel.mf b/usr/src/pkg/manifests/system-kernel.mf
index a1152c7d29..5d4a719b58 100644
--- a/usr/src/pkg/manifests/system-kernel.mf
+++ b/usr/src/pkg/manifests/system-kernel.mf
@@ -214,8 +214,6 @@ driver name=rts perms="rts 0666 root sys"
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)/random group=sys
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 @@ $(i386_ONLY)file path=kernel/drv/scsi_vhci group=sys
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
diff --git a/usr/src/pkg/manifests/system-library.mf b/usr/src/pkg/manifests/system-library.mf
index 6823b4149e..4bf5e75395 100644
--- a/usr/src/pkg/manifests/system-library.mf
+++ b/usr/src/pkg/manifests/system-library.mf
@@ -181,6 +181,7 @@ file path=lib/libgen.so.1
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
diff --git a/usr/src/pkg/manifests/system-network.mf b/usr/src/pkg/manifests/system-network.mf
index 14e3840ade..fe17448d86 100644
--- a/usr/src/pkg/manifests/system-network.mf
+++ b/usr/src/pkg/manifests/system-network.mf
@@ -40,6 +40,7 @@ dir path=etc/inet/ike/crls group=sys
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/ike.preshared group=sys mode=0600 \
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/dlstat mode=0555
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" \
diff --git a/usr/src/tools/scripts/bfu.sh b/usr/src/tools/scripts/bfu.sh
index 0ea2212622..657b063139 100644
--- a/usr/src/tools/scripts/bfu.sh
+++ b/usr/src/tools/scripts/bfu.sh
@@ -93,6 +93,7 @@ all_zones_files="
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 @@ EOFA
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 @@ bfucmd="
/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 @@ bfucmd="
/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 @@ mondo_loop() {
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
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 43bee44792..40d04be785 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -529,24 +529,25 @@ IP_ICMP_OBJS = icmp.o icmp_opt_data.o
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 @@ TCP_OBJS += tcpddi.o
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
diff --git a/usr/src/uts/common/inet/Makefile b/usr/src/uts/common/inet/Makefile
index a5da360b01..14ce78a884 100644
--- a/usr/src/uts/common/inet/Makefile
+++ b/usr/src/uts/common/inet/Makefile
@@ -32,7 +32,7 @@ HDRS= arp.h common.h ipclassifier.h ip.h ip6.h ipdrop.h ipnet.h \
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
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h
index ba57cf4406..b8bd229b5a 100644
--- a/usr/src/uts/common/inet/ip.h
+++ b/usr/src/uts/common/inet/ip.h
@@ -174,11 +174,11 @@ typedef struct ipoptp_s
#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 @@ typedef struct ipif_s {
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 @@ typedef struct ipif_s {
* 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 @@ typedef struct ill_s {
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 @@ typedef struct ill_s {
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 @@ enum {
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 @@ extern vmem_t *ip_minor_arena_la;
* /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
diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c
index e2eed17eb2..b0ecad4317 100644
--- a/usr/src/uts/common/inet/ip/icmp.c
+++ b/usr/src/uts/common/inet/ip/icmp.c
@@ -128,10 +128,6 @@ int icmp_opt_get(conn_t *connp, int level, int name,
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 @@ static struct T_info_ack icmp_g_t_info_ack = {
};
/*
- * 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 @@ icmp_build_hdr_template(conn_t *connp, const in6_addr_t *v6src,
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 @@ icmp_wput_other(queue_t *q, mblk_t *mp)
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 @@ icmp_wput_other(queue_t *q, mblk_t *mp)
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 @@ static void *
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));
+ 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);
- (void) icmp_param_register(&is->is_nd,
- is->is_param_arr, A_CNT(icmp_param_arr));
is->is_ksp = rawip_kstat_init(stackid);
major = mod_name_to_major(INET_NAME);
@@ -5019,9 +4983,8 @@ rawip_stack_fini(netstackid_t stackid, void *arg)
{
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 @@ rawip_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
}
switch (cmd) {
- case ND_SET:
- case ND_GET:
case _SIOCSOCKFALLBACK:
case TI_GETPEERNAME:
case TI_GETMYNAME:
diff --git a/usr/src/uts/common/inet/ip/igmp.c b/usr/src/uts/common/inet/ip/igmp.c
index daed958617..470c0afb24 100644
--- a/usr/src/uts/common/inet/ip/igmp.c
+++ b/usr/src/uts/common/inet/ip/igmp.c
@@ -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>
diff --git a/usr/src/uts/common/inet/ip/ip.c b/usr/src/uts/common/inet/ip/ip.c
index 0a84ee99a8..31febd92bb 100644
--- a/usr/src/uts/common/inet/ip/ip.c
+++ b/usr/src/uts/common/inet/ip/ip.c
@@ -299,11 +299,6 @@ void (*cl_inet_idlesa)(netstackid_t, uint8_t, uint32_t, sa_family_t,
* - 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 @@ boolean_t ip_squeue_fanout = 0;
*/
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 char *ip_dot_saddr(uchar_t *, char *);
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_init(netstackid_t stackid, netstack_t *ns);
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 @@ static void ipobs_fini(ip_stack_t *);
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_debug;
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 @@ ip_ioctl_cmd_t ip_ndx_ioctl_table[] = {
/* 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 @@ ip_stack_fini(netstackid_t stackid, void *arg)
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 @@ static void *
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 @@ ip_stack_init(netstackid_t stackid, netstack_t *ns)
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_stack_init(netstackid_t stackid, netstack_t *ns)
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 @@ ip_fill_mtuinfo(conn_t *connp, ip_xmit_attr_t *ixa, struct ip6_mtuinfo *mtuinfo)
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 @@ ip_param_register(IDP *ndp, ipparam_t *ippa, size_t ippa_cnt,
* 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 @@ ip_ire_rebind_walker(ire_t *ire, void *notused)
* (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 @@ ip_ire_unbind_walker(ire_t *ire, void *notused)
* 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 @@ conn_ire_revalidate(conn_t *connp, void *arg)
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_frag_timer(void *arg)
{
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_frag_timer(void *arg)
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 @@ ill_frag_timer(void *arg)
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 @@ ill_frag_timer_start(ill_t *ill)
}
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 @@ ip_snmp_get_mib2_ip(queue_t *q, mblk_t *mpctl, mib2_ipIfStatsEntry_t *ipmib,
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 @@ ip_snmp_get_mib2_ip_traffic_stats(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_snmp_get_mib2_ip_traffic_stats(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_snmp_get_mib2_ip_addr(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_snmp_get_mib2_ip6_addr(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_snmp_get_mib2_ip6(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_snmp_get_mib2_ip6(queue_t *q, mblk_t *mpctl, ip_stack_t *ipst)
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 @@ ip_multirt_apply_membership(int (*fn)(conn_t *, boolean_t,
}
/*
- * 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 @@ ip_squeue_switch(int val)
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 @@ ip_kstat_init(netstackid_t stackid, ip_stack_t *ipst)
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 @@ ip_kstat_update(kstat_t *kp, int rw)
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;
diff --git a/usr/src/uts/common/inet/ip/ip6_if.c b/usr/src/uts/common/inet/ip/ip6_if.c
index a9dc126ae0..e4826bb1a2 100644
--- a/usr/src/uts/common/inet/ip/ip6_if.c
+++ b/usr/src/uts/common/inet/ip/ip6_if.c
@@ -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 @@ ipif_setlinklocal(ipif_t *ipif)
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.
*/
diff --git a/usr/src/uts/common/inet/ip/ip6_ire.c b/usr/src/uts/common/inet/ip/ip6_ire.c
index 0b84c0a2d9..e02f4fef87 100644
--- a/usr/src/uts/common/inet/ip/ip6_ire.c
+++ b/usr/src/uts/common/inet/ip/ip6_ire.c
@@ -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>
diff --git a/usr/src/uts/common/inet/ip/ip_if.c b/usr/src/uts/common/inet/ip/ip_if.c
index 21d66b0aff..5c7b406001 100644
--- a/usr/src/uts/common/inet/ip/ip_if.c
+++ b/usr/src/uts/common/inet/ip/ip_if.c
@@ -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 ip_m_t ip_m_tbl[] = {
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 @@ ill_delete_tail(ill_t *ill)
{
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 @@ ill_delete_tail(ill_t *ill)
*/
(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 @@ ill_frag_free_pkts(ill_t *ill, ipfb_t *ipfb, ipf_t *ipf, int free_cnt)
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 @@ ill_set_nce_router_flags(ill_t *ill, boolean_t enable)
}
/*
- * 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 @@ ill_init(queue_t *q, ill_t *ill)
* 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 @@ ip_mcast_mapping(ill_t *ill, uchar_t *addr, uchar_t *hwaddr)
}
/*
+ * 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 @@ ip_rt_add(ipaddr_t dst_addr, ipaddr_t mask, ipaddr_t gw_addr,
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 @@ ip_sioctl_lookup(int ioc_cmd)
}
/*
+ * 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 @@ ip_sioctl_copyin_setup(queue_t *q, mblk_t *mp)
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 @@ ip_sioctl_copyin_setup(queue_t *q, mblk_t *mp)
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_copyin_setup(queue_t *q, mblk_t *mp)
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 @@ ip_sioctl_removeif_restart(ipif_t *ipif, sin_t *dummy_sin, queue_t *q,
}
/*
+ * 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 @@ ip_sioctl_addr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
/*
* 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 @@ ip_sioctl_addr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_addr_tail(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
* 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 @@ ip_sioctl_dstaddr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_brdaddr(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_netmask(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_metric(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_get_metric(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ipif_clone(const ipif_t *sipif, ipif_t *dipif)
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 @@ ip_sioctl_slifname(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
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 @@ ip_sioctl_slifusesrc(ipif_t *ipif, sin_t *sin, queue_t *q, mblk_t *mp,
}
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 @@ done:
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 @@ ipif_set_values_tail(ill_t *ill, ipif_t *ipif, mblk_t *mp, queue_t *q)
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 @@ ipif_set_values(queue_t *q, mblk_t *mp, char *interf_name, uint_t *new_ppa_ptr)
* 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 @@ ipif_set_values(queue_t *q, mblk_t *mp, char *interf_name, uint_t *new_ppa_ptr)
* 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 @@ ipif_set_values(queue_t *q, mblk_t *mp, char *interf_name, uint_t *new_ppa_ptr)
* 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;
}
diff --git a/usr/src/uts/common/inet/ip/ip_ire.c b/usr/src/uts/common/inet/ip/ip_ire.c
index 85e9570916..9c457d0489 100644
--- a/usr/src/uts/common/inet/ip/ip_ire.c
+++ b/usr/src/uts/common/inet/ip/ip_ire.c
@@ -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>
diff --git a/usr/src/uts/common/inet/ip/ip_mroute.c b/usr/src/uts/common/inet/ip/ip_mroute.c
index 0ad211dd5b..973afd04e7 100644
--- a/usr/src/uts/common/inet/ip/ip_mroute.c
+++ b/usr/src/uts/common/inet/ip/ip_mroute.c
@@ -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 @@ ip_mrouter_init(conn_t *connp, uchar_t *data, int datalen, ip_stack_t *ipst)
(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 @@ ip_mrouter_done(ip_stack_t *ipst)
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;
}
/*
diff --git a/usr/src/uts/common/inet/ip/ip_rts.c b/usr/src/uts/common/inet/ip/ip_rts.c
index 8a44a0bcd4..9486945532 100644
--- a/usr/src/uts/common/inet/ip/ip_rts.c
+++ b/usr/src/uts/common/inet/ip/ip_rts.c
@@ -1351,7 +1351,8 @@ rts_getifdata(if_data_t *if_data, const ipif_t *ipif)
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 @@ rts_new_rtsmsg(int cmd, int error, const ipif_t *ipif, uint_t flags)
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 {
diff --git a/usr/src/uts/common/inet/ip/ip_tunables.c b/usr/src/uts/common/inet/ip/ip_tunables.c
new file mode 100644
index 0000000000..d78639f1bf
--- /dev/null
+++ b/usr/src/uts/common/inet/ip/ip_tunables.c
@@ -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);
diff --git a/usr/src/uts/common/inet/ip_if.h b/usr/src/uts/common/inet/ip_if.h
index 1ded817625..c1ffa33189 100644
--- a/usr/src/uts/common/inet/ip_if.h
+++ b/usr/src/uts/common/inet/ip_if.h
@@ -80,7 +80,7 @@ extern "C" {
#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 @@ extern "C" {
#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_siocaddrt(ipif_t *, sin_t *, queue_t *, mblk_t *,
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_slifusesrc(ipif_t *, sin_t *, queue_t *,
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);
diff --git a/usr/src/uts/common/inet/ip_impl.h b/usr/src/uts/common/inet/ip_impl.h
index 694f7a63b0..2b37528eb9 100644
--- a/usr/src/uts/common/inet/ip_impl.h
+++ b/usr/src/uts/common/inet/ip_impl.h
@@ -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 @@ extern "C" {
#include <sys/sdt.h>
#include <sys/dld.h>
+#include <inet/tunables.h>
#define IP_MOD_ID 5701
@@ -179,6 +180,9 @@ extern zoneid_t ip_get_zoneid_v4(ipaddr_t, mblk_t *, ip_recv_attr_t *,
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
diff --git a/usr/src/uts/common/inet/ip_stack.h b/usr/src/uts/common/inet/ip_stack.h
index d2f6c07234..a564376cfb 100644
--- a/usr/src/uts/common/inet/ip_stack.h
+++ b/usr/src/uts/common/inet/ip_stack.h
@@ -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 @@ struct ip_stack {
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 @@ struct ip_stack {
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 @@ struct ip_stack {
/* 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 @@ struct ip_stack {
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 @@ struct ip_stack {
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;
diff --git a/usr/src/uts/common/inet/nd.c b/usr/src/uts/common/inet/nd.c
index cf903733b7..58f80a8330 100644
--- a/usr/src/uts/common/inet/nd.c
+++ b/usr/src/uts/common/inet/nd.c
@@ -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 @@ nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
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 @@ nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
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);
}
diff --git a/usr/src/uts/common/inet/rawip_impl.h b/usr/src/uts/common/inet/rawip_impl.h
index 348c4f5239..71b4f3f228 100644
--- a/usr/src/uts/common/inet/rawip_impl.h
+++ b/usr/src/uts/common/inet/rawip_impl.h
@@ -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 @@ extern "C" {
#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 @@ typedef struct icmpparam_s {
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;
diff --git a/usr/src/uts/common/inet/sctp/sctp.c b/usr/src/uts/common/inet/sctp/sctp.c
index 5dab2ba37d..77d15a5e6d 100644
--- a/usr/src/uts/common/inet/sctp/sctp.c
+++ b/usr/src/uts/common/inet/sctp/sctp.c
@@ -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 @@ int sctp_recvq_tq_task_min = 5;
/* 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 @@ static void *
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 @@ sctp_stack_init(netstackid_t stackid, netstack_t *ns)
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_fini(netstackid_t stackid, void *arg)
{
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);
diff --git a/usr/src/uts/common/inet/sctp/sctp_impl.h b/usr/src/uts/common/inet/sctp/sctp_impl.h
index 0eaa790a11..5823e03de2 100644
--- a/usr/src/uts/common/inet/sctp/sctp_impl.h
+++ b/usr/src/uts/common/inet/sctp/sctp_impl.h
@@ -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 @@ typedef struct sctpt_s {
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 mblk_t *sctp_make_sack(sctp_t *, sctp_faddr_t *, mblk_t *);
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(const sctp_t *, void *, int);
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_user_abort(sctp_t *, mblk_t *);
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 *);
diff --git a/usr/src/uts/common/inet/sctp/sctp_ioc.c b/usr/src/uts/common/inet/sctp/sctp_ioc.c
deleted file mode 100644
index aecf61002e..0000000000
--- a/usr/src/uts/common/inet/sctp/sctp_ioc.c
+++ /dev/null
@@ -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;
- }
-}
diff --git a/usr/src/uts/common/inet/sctp/sctp_param.c b/usr/src/uts/common/inet/sctp/sctp_param.c
deleted file mode 100644
index 26365c5a06..0000000000
--- a/usr/src/uts/common/inet/sctp/sctp_param.c
+++ /dev/null
@@ -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;
-
-}
diff --git a/usr/src/uts/common/inet/sctp/sctp_stack.h b/usr/src/uts/common/inet/sctp/sctp_stack.h
index e9ad5cf9c7..c4c6b4955f 100644
--- a/usr/src/uts/common/inet/sctp/sctp_stack.h
+++ b/usr/src/uts/common/inet/sctp/sctp_stack.h
@@ -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 @@ struct sctp_stack {
#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_stack {
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;
diff --git a/usr/src/uts/common/inet/sctp/sctp_tunables.c b/usr/src/uts/common/inet/sctp/sctp_tunables.c
new file mode 100644
index 0000000000..8d3bd6fb52
--- /dev/null
+++ b/usr/src/uts/common/inet/sctp/sctp_tunables.c
@@ -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);
diff --git a/usr/src/uts/common/inet/sctp_ip.h b/usr/src/uts/common/inet/sctp_ip.h
index 9e4c2ef7ec..95c74bcbfe 100644
--- a/usr/src/uts/common/inet/sctp_ip.h
+++ b/usr/src/uts/common/inet/sctp_ip.h
@@ -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 @@ extern conn_t *sctp_fanout(in6_addr_t *, in6_addr_t *, uint32_t,
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 *);
diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c
index 63f99b1282..2cc0377fd4 100644
--- a/usr/src/uts/common/inet/tcp/tcp.c
+++ b/usr/src/uts/common/inet/tcp/tcp.c
@@ -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_ipv4(tcp_t *tcp, ipaddr_t *dstaddrp,
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 @@ struct T_info_ack tcp_g_t_info_ack_v6 = {
(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 @@ tcp_disconnect(tcp_t *tcp, mblk_t *mp)
}
/*
- * 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 @@ tcp_build_hdrs(tcp_t *tcp)
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 @@ tcp_random(void)
#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 @@ tcp_iss_key_init(uint8_t *phrase, int len, tcp_stack_t *tcps)
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 @@ static void *
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 @@ tcp_stack_init(netstackid_t stackid, netstack_t *ns)
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_stack_init(netstackid_t stackid, netstack_t *ns)
/* 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 @@ tcp_stack_fini(netstackid_t stackid, void *arg)
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);
diff --git a/usr/src/uts/common/inet/tcp/tcp_misc.c b/usr/src/uts/common/inet/tcp/tcp_misc.c
index dfea8c8b0e..556df3a1d3 100644
--- a/usr/src/uts/common/inet/tcp/tcp_misc.c
+++ b/usr/src/uts/common/inet/tcp/tcp_misc.c
@@ -632,102 +632,6 @@ tcp_find_listener_conf(tcp_stack_t *tcps, in_port_t port)
}
/*
- * 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
diff --git a/usr/src/uts/common/inet/tcp/tcp_output.c b/usr/src/uts/common/inet/tcp/tcp_output.c
index 01b383bb34..2a02d214f5 100644
--- a/usr/src/uts/common/inet/tcp/tcp_output.c
+++ b/usr/src/uts/common/inet/tcp/tcp_output.c
@@ -90,7 +90,6 @@ tcp_wput(queue_t *q, mblk_t *mp)
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 @@ tcp_wput(queue_t *q, mblk_t *mp)
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;
diff --git a/usr/src/uts/common/inet/tcp/tcp_tunables.c b/usr/src/uts/common/inet/tcp/tcp_tunables.c
new file mode 100644
index 0000000000..1d01d9a1b1
--- /dev/null
+++ b/usr/src/uts/common/inet/tcp/tcp_tunables.c
@@ -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);
diff --git a/usr/src/uts/common/inet/tcp_impl.h b/usr/src/uts/common/inet/tcp_impl.h
index 2ee2b6cb39..a7d27350b3 100644
--- a/usr/src/uts/common/inet/tcp_impl.h
+++ b/usr/src/uts/common/inet/tcp_impl.h
@@ -43,6 +43,7 @@ extern "C" {
#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 @@ extern sock_downcalls_t sock_tcp_downcalls;
*/
#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 @@ extern uint32_t tcp_early_abort;
#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 boolean_t tcp_fuse_rcv_drain(queue_t *, tcp_t *, mblk_t **);
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 void tcp_time_wait_processing(tcp_t *, mblk_t *, uint32_t,
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 */
diff --git a/usr/src/uts/common/inet/tcp_stack.h b/usr/src/uts/common/inet/tcp_stack.h
index 1a6e374f3e..5cff22c5f0 100644
--- a/usr/src/uts/common/inet/tcp_stack.h
+++ b/usr/src/uts/common/inet/tcp_stack.h
@@ -52,7 +52,7 @@ struct tcp_stack {
*/
#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 @@ struct tcp_stack {
*/
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;
diff --git a/usr/src/uts/common/inet/tunables.c b/usr/src/uts/common/inet/tunables.c
new file mode 100644
index 0000000000..e9926151f0
--- /dev/null
+++ b/usr/src/uts/common/inet/tunables.c
@@ -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);
+}
diff --git a/usr/src/uts/common/inet/tunables.h b/usr/src/uts/common/inet/tunables.h
new file mode 100644
index 0000000000..bf7c908d3f
--- /dev/null
+++ b/usr/src/uts/common/inet/tunables.h
@@ -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 */
diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c
index fc9842bb7d..79eaab55a5 100644
--- a/usr/src/uts/common/inet/udp/udp.c
+++ b/usr/src/uts/common/inet/udp/udp.c
@@ -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_lastdst(conn_t *connp, mblk_t *mp, cred_t *cr,
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 @@ int udp_getpeername(sock_lower_handle_t,
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 @@ static struct T_info_ack udp_g_t_info_ack_ipv6 = {
(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 @@ udp_err_ack_prim(queue_t *q, mblk_t *mp, t_scalar_t primitive,
}
}
-/*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 @@ udp_build_hdr_template(conn_t *connp, const in6_addr_t *v6src,
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 @@ udp_wput_other(queue_t *q, mblk_t *mp)
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 @@ udp_wput_other(queue_t *q, mblk_t *mp)
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 @@ static void *
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 @@ udp_stack_init(netstackid_t stackid, netstack_t *ns)
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 @@ udp_stack_fini(netstackid_t stackid, void *arg)
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 @@ udp_stack_fini(netstackid_t stackid, void *arg)
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 @@ udp_ioctl(sock_lower_handle_t proto_handle, int cmd, intptr_t arg,
}
switch (cmd) {
- case ND_SET:
- case ND_GET:
case _SIOCSOCKFALLBACK:
case TI_GETPEERNAME:
case TI_GETMYNAME:
diff --git a/usr/src/uts/common/inet/udp/udp_tunables.c b/usr/src/uts/common/inet/udp/udp_tunables.c
new file mode 100644
index 0000000000..ce43dd2cd9
--- /dev/null
+++ b/usr/src/uts/common/inet/udp/udp_tunables.c
@@ -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);
diff --git a/usr/src/uts/common/inet/udp_impl.h b/usr/src/uts/common/inet/udp_impl.h
index 4da82a0377..11ca9f9810 100644
--- a/usr/src/uts/common/inet/udp_impl.h
+++ b/usr/src/uts/common/inet/udp_impl.h
@@ -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 @@ extern "C" {
#include <inet/common.h>
#include <inet/ip.h>
#include <inet/optcom.h>
+#include <inet/tunables.h>
#define UDP_MOD_ID 5607
@@ -89,16 +90,14 @@ typedef struct udp_stat { /* Class "net" kstats */
} 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
+/* 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 @@ struct udp_stack {
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 @@ typedef struct udpahdr_s {
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) \
diff --git a/usr/src/uts/common/io/strplumb.c b/usr/src/uts/common/io/strplumb.c
index 473f7bc72e..1a3cb37248 100644
--- a/usr/src/uts/common/io/strplumb.c
+++ b/usr/src/uts/common/io/strplumb.c
@@ -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 @@ _info(struct modinfo *modinfop)
#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 @@ _info(struct modinfo *modinfop)
#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 @@ static strplumb_modspec_t strplumb_modlist[] = {
{ "drv", TCP6 },
{ "drv", UDP },
{ "drv", UDP6 },
- { "drv", SCTP },
- { "drv", SCTP6 },
{ "drv", ICMP },
{ "drv", ICMP6 },
{ "drv", ARP },
diff --git a/usr/src/uts/common/net/if.h b/usr/src/uts/common/net/if.h
index d92a4ff6c3..41457e2edb 100644
--- a/usr/src/uts/common/net/if.h
+++ b/usr/src/uts/common/net/if.h
@@ -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 @@ struct ifnet {
#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 @@ struct lifreq {
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 @@ struct lifreq {
#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 @@ struct sioc_lsg_req {
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 @@ struct lifsrcof {
#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)
diff --git a/usr/src/uts/common/sys/sockio.h b/usr/src/uts/common/sys/sockio.h
index 0fca7c5c43..b81c30b373 100644
--- a/usr/src/uts/common/sys/sockio.h
+++ b/usr/src/uts/common/sys/sockio.h
@@ -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 @@ extern "C" {
*/
#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
diff --git a/usr/src/uts/intel/Makefile.intel.shared b/usr/src/uts/intel/Makefile.intel.shared
index fe175e3d5e..8ee27ab393 100644
--- a/usr/src/uts/intel/Makefile.intel.shared
+++ b/usr/src/uts/intel/Makefile.intel.shared
@@ -318,8 +318,6 @@ DRV_KMODS += rum
DRV_KMODS += rwd
DRV_KMODS += rwn
DRV_KMODS += sad
-DRV_KMODS += sctp
-DRV_KMODS += sctp6
DRV_KMODS += sd
DRV_KMODS += sdcard
DRV_KMODS += sdhost
diff --git a/usr/src/uts/intel/ip/ip.global-objs.debug64 b/usr/src/uts/intel/ip/ip.global-objs.debug64
index bfad66f0a2..acaa8bfec6 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.debug64
+++ b/usr/src/uts/intel/ip/ip.global-objs.debug64
@@ -76,7 +76,7 @@ icmp_max_optsize
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_count
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_policy_failure_msgs
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_gw_secattr_cache
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_conn_hash_size
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_min_conn_listener
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_max_optsize
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
diff --git a/usr/src/uts/intel/ip/ip.global-objs.obj64 b/usr/src/uts/intel/ip/ip.global-objs.obj64
index 0d3f7a73f7..8f1eaf800e 100644
--- a/usr/src/uts/intel/ip/ip.global-objs.obj64
+++ b/usr/src/uts/intel/ip/ip.global-objs.obj64
@@ -76,7 +76,7 @@ icmp_max_optsize
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_count
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_policy_failure_msgs
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_gw_secattr_cache
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_conn_hash_size
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_min_conn_listener
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_max_optsize
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
diff --git a/usr/src/uts/intel/sctp/Makefile b/usr/src/uts/intel/sctp/Makefile
deleted file mode 100644
index 94ec17f3c6..0000000000
--- a/usr/src/uts/intel/sctp/Makefile
+++ /dev/null
@@ -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
diff --git a/usr/src/uts/intel/sctp6/Makefile b/usr/src/uts/intel/sctp6/Makefile
deleted file mode 100644
index f53a6e849f..0000000000
--- a/usr/src/uts/intel/sctp6/Makefile
+++ /dev/null
@@ -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
diff --git a/usr/src/uts/sparc/Makefile.sparc.shared b/usr/src/uts/sparc/Makefile.sparc.shared
index 0fbac6b400..7ce341b003 100644
--- a/usr/src/uts/sparc/Makefile.sparc.shared
+++ b/usr/src/uts/sparc/Makefile.sparc.shared
@@ -212,7 +212,7 @@ DRV_KMODS += pseudo ptc ptm pts ptsl ramdisk random rsm rts sad
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
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.debug64 b/usr/src/uts/sparc/ip/ip.global-objs.debug64
index bfad66f0a2..acaa8bfec6 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.debug64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.debug64
@@ -76,7 +76,7 @@ icmp_max_optsize
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_count
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_policy_failure_msgs
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_gw_secattr_cache
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_conn_hash_size
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_min_conn_listener
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_max_optsize
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
diff --git a/usr/src/uts/sparc/ip/ip.global-objs.obj64 b/usr/src/uts/sparc/ip/ip.global-objs.obj64
index 0d3f7a73f7..8f1eaf800e 100644
--- a/usr/src/uts/sparc/ip/ip.global-objs.obj64
+++ b/usr/src/uts/sparc/ip/ip.global-objs.obj64
@@ -76,7 +76,7 @@ icmp_max_optsize
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_count
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_policy_failure_msgs
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_gw_secattr_cache
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_conn_hash_size
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_min_conn_listener
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_max_optsize
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
diff --git a/usr/src/uts/sparc/sctp/Makefile b/usr/src/uts/sparc/sctp/Makefile
deleted file mode 100644
index c06523e32f..0000000000
--- a/usr/src/uts/sparc/sctp/Makefile
+++ /dev/null
@@ -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
diff --git a/usr/src/uts/sparc/sctp6/Makefile b/usr/src/uts/sparc/sctp6/Makefile
deleted file mode 100644
index 215320f438..0000000000
--- a/usr/src/uts/sparc/sctp6/Makefile
+++ /dev/null
@@ -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