xref: /titanic_52/usr/src/cmd/cmd-inet/lib/ipmgmtd/ipmgmt_persist.c (revision 8887b57dc579de11464fc6c74163d2595ce073af)
16e91bba0SGirish Moodalbail /*
26e91bba0SGirish Moodalbail  * CDDL HEADER START
36e91bba0SGirish Moodalbail  *
46e91bba0SGirish Moodalbail  * The contents of this file are subject to the terms of the
56e91bba0SGirish Moodalbail  * Common Development and Distribution License (the "License").
66e91bba0SGirish Moodalbail  * You may not use this file except in compliance with the License.
76e91bba0SGirish Moodalbail  *
86e91bba0SGirish Moodalbail  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96e91bba0SGirish Moodalbail  * or http://www.opensolaris.org/os/licensing.
106e91bba0SGirish Moodalbail  * See the License for the specific language governing permissions
116e91bba0SGirish Moodalbail  * and limitations under the License.
126e91bba0SGirish Moodalbail  *
136e91bba0SGirish Moodalbail  * When distributing Covered Code, include this CDDL HEADER in each
146e91bba0SGirish Moodalbail  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156e91bba0SGirish Moodalbail  * If applicable, add the following below this CDDL HEADER, with the
166e91bba0SGirish Moodalbail  * fields enclosed by brackets "[]" replaced with your own identifying
176e91bba0SGirish Moodalbail  * information: Portions Copyright [yyyy] [name of copyright owner]
186e91bba0SGirish Moodalbail  *
196e91bba0SGirish Moodalbail  * CDDL HEADER END
206e91bba0SGirish Moodalbail  */
216e91bba0SGirish Moodalbail 
226e91bba0SGirish Moodalbail /*
23ec3706caSVasumathi Sundaram  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246e91bba0SGirish Moodalbail  */
256e91bba0SGirish Moodalbail 
266e91bba0SGirish Moodalbail /*
276e91bba0SGirish Moodalbail  * Contains DB walker functions, which are of type `db_wfunc_t';
286e91bba0SGirish Moodalbail  *
296e91bba0SGirish Moodalbail  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
306e91bba0SGirish Moodalbail  *				size_t bufsize, int *errp);
316e91bba0SGirish Moodalbail  *
326e91bba0SGirish Moodalbail  * ipadm_rw_db() walks through the data store, one line at a time and calls
336e91bba0SGirish Moodalbail  * these call back functions with:
346e91bba0SGirish Moodalbail  *	`cbarg'  - callback argument
356e91bba0SGirish Moodalbail  *	`db_nvl' - representing a line from DB in nvlist_t form
366e91bba0SGirish Moodalbail  *	`buf'	 - character buffer to hold modified line
376e91bba0SGirish Moodalbail  *	`bufsize'- size of the buffer
386e91bba0SGirish Moodalbail  *	`errp' - captures any error inside the walker function.
396e91bba0SGirish Moodalbail  *
406e91bba0SGirish Moodalbail  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
416e91bba0SGirish Moodalbail  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
426e91bba0SGirish Moodalbail  * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
436e91bba0SGirish Moodalbail  * the modified `buf' is written back into DB.
446e91bba0SGirish Moodalbail  *
456e91bba0SGirish Moodalbail  * All the 'read' callback functions, retrieve the information from the DB, by
466e91bba0SGirish Moodalbail  * reading `db_nvl' and then populate the `cbarg'.
476e91bba0SGirish Moodalbail  */
486e91bba0SGirish Moodalbail 
496e91bba0SGirish Moodalbail #include <stdlib.h>
506e91bba0SGirish Moodalbail #include <strings.h>
516e91bba0SGirish Moodalbail #include <errno.h>
526e91bba0SGirish Moodalbail #include <assert.h>
536e91bba0SGirish Moodalbail #include <sys/types.h>
546e91bba0SGirish Moodalbail #include <sys/socket.h>
556e91bba0SGirish Moodalbail #include <netinet/in.h>
566e91bba0SGirish Moodalbail #include <arpa/inet.h>
576e91bba0SGirish Moodalbail #include <unistd.h>
586e91bba0SGirish Moodalbail #include "ipmgmt_impl.h"
59*8887b57dSGirish Moodalbail 
60*8887b57dSGirish Moodalbail /* SCF related property group names and property names */
61*8887b57dSGirish Moodalbail #define	IPMGMTD_APP_PG		"ipmgmtd"
62*8887b57dSGirish Moodalbail #define	IPMGMTD_PROP_FBD	"first_boot_done"
63*8887b57dSGirish Moodalbail #define	IPMGMTD_PROP_DBVER	"datastore_version"
64*8887b57dSGirish Moodalbail #define	IPMGMTD_TRUESTR		"true"
656e91bba0SGirish Moodalbail 
666e91bba0SGirish Moodalbail #define	ATYPE	"_atype"		/* name of the address type nvpair */
676e91bba0SGirish Moodalbail #define	FLAGS	"_flags"		/* name of the flags nvpair */
686e91bba0SGirish Moodalbail 
696e91bba0SGirish Moodalbail /*
706e91bba0SGirish Moodalbail  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
716e91bba0SGirish Moodalbail  * IPADM_ADDR_IPV6_ADDRCONF.
726e91bba0SGirish Moodalbail  */
736e91bba0SGirish Moodalbail #define	IPMGMT_ATYPE_V6ACONF	0x1
746e91bba0SGirish Moodalbail 
756e91bba0SGirish Moodalbail extern pthread_rwlock_t ipmgmt_dbconf_lock;
766e91bba0SGirish Moodalbail 
779b5bf10aSMark Haywood /* signifies whether volatile copy of data store is in use */
789b5bf10aSMark Haywood static boolean_t ipmgmt_rdonly_root = B_FALSE;
799b5bf10aSMark Haywood 
806e91bba0SGirish Moodalbail /*
816e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
826e91bba0SGirish Moodalbail  * in private nvpairs `proto', `ifname' & `aobjname'.
836e91bba0SGirish Moodalbail  */
846e91bba0SGirish Moodalbail static boolean_t
856e91bba0SGirish Moodalbail ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
866e91bba0SGirish Moodalbail     const char *aobjname)
876e91bba0SGirish Moodalbail {
886e91bba0SGirish Moodalbail 	char		*db_proto = NULL, *db_ifname = NULL;
896e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
906e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
916e91bba0SGirish Moodalbail 	char		*name;
926e91bba0SGirish Moodalbail 
936e91bba0SGirish Moodalbail 	/* walk through db_nvl and retrieve all its private nvpairs */
946e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
956e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
966e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
976e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
986e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_proto);
996e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
1006e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
1016e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
1026e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
1036e91bba0SGirish Moodalbail 	}
1046e91bba0SGirish Moodalbail 
1056e91bba0SGirish Moodalbail 	if (proto != NULL && proto[0] == '\0')
1066e91bba0SGirish Moodalbail 		proto = NULL;
1076e91bba0SGirish Moodalbail 	if (ifname != NULL && ifname[0] == '\0')
1086e91bba0SGirish Moodalbail 		ifname = NULL;
1096e91bba0SGirish Moodalbail 	if (aobjname != NULL && aobjname[0] == '\0')
1106e91bba0SGirish Moodalbail 		aobjname = NULL;
1116e91bba0SGirish Moodalbail 
1126e91bba0SGirish Moodalbail 	if ((proto == NULL && db_proto != NULL) ||
1136e91bba0SGirish Moodalbail 	    (proto != NULL && db_proto == NULL) ||
1146e91bba0SGirish Moodalbail 	    strcmp(proto, db_proto) != 0) {
1156e91bba0SGirish Moodalbail 		/* no intersection - different protocols. */
1166e91bba0SGirish Moodalbail 		return (B_FALSE);
1176e91bba0SGirish Moodalbail 	}
1186e91bba0SGirish Moodalbail 	if ((ifname == NULL && db_ifname != NULL) ||
1196e91bba0SGirish Moodalbail 	    (ifname != NULL && db_ifname == NULL) ||
1206e91bba0SGirish Moodalbail 	    strcmp(ifname, db_ifname) != 0) {
1216e91bba0SGirish Moodalbail 		/* no intersection - different interfaces. */
1226e91bba0SGirish Moodalbail 		return (B_FALSE);
1236e91bba0SGirish Moodalbail 	}
1246e91bba0SGirish Moodalbail 	if ((aobjname == NULL && db_aobjname != NULL) ||
1256e91bba0SGirish Moodalbail 	    (aobjname != NULL && db_aobjname == NULL) ||
1266e91bba0SGirish Moodalbail 	    strcmp(aobjname, db_aobjname) != 0) {
1276e91bba0SGirish Moodalbail 		/* no intersection - different address objects */
1286e91bba0SGirish Moodalbail 		return (B_FALSE);
1296e91bba0SGirish Moodalbail 	}
1306e91bba0SGirish Moodalbail 
1316e91bba0SGirish Moodalbail 	return (B_TRUE);
1326e91bba0SGirish Moodalbail }
1336e91bba0SGirish Moodalbail 
1346e91bba0SGirish Moodalbail /*
1356e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
1366e91bba0SGirish Moodalbail  */
1376e91bba0SGirish Moodalbail static boolean_t
1386e91bba0SGirish Moodalbail ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
1396e91bba0SGirish Moodalbail {
1406e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
1416e91bba0SGirish Moodalbail 	char		*name;
1426e91bba0SGirish Moodalbail 	char		*proto = NULL, *ifname = NULL, *aobjname = NULL;
1436e91bba0SGirish Moodalbail 
1446e91bba0SGirish Moodalbail 	/* walk through in_nvl and retrieve all its private nvpairs */
1456e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
1466e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
1476e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
1486e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
1496e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &proto);
1506e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
1516e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &ifname);
1526e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
1536e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &aobjname);
1546e91bba0SGirish Moodalbail 	}
1556e91bba0SGirish Moodalbail 
1566e91bba0SGirish Moodalbail 	return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
1576e91bba0SGirish Moodalbail }
1586e91bba0SGirish Moodalbail 
1596e91bba0SGirish Moodalbail /*
1606e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
1616e91bba0SGirish Moodalbail  * in private nvpairs `proto', `ifname' & `aobjname'.
1626e91bba0SGirish Moodalbail  */
1636e91bba0SGirish Moodalbail static boolean_t
1646e91bba0SGirish Moodalbail ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
1656e91bba0SGirish Moodalbail     const char *ifname, char *aobjname)
1666e91bba0SGirish Moodalbail {
1676e91bba0SGirish Moodalbail 	char		*db_ifname = NULL, *db_proto = NULL;
1686e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
1696e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
1706e91bba0SGirish Moodalbail 	char		*name;
1716e91bba0SGirish Moodalbail 
1726e91bba0SGirish Moodalbail 	/* walk through db_nvl and retrieve all private nvpairs */
1736e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1746e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1756e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
1766e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
1776e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_proto);
1786e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
1796e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
1806e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
1816e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
1826e91bba0SGirish Moodalbail 	}
1836e91bba0SGirish Moodalbail 
1846e91bba0SGirish Moodalbail 	if (proto != NULL && proto[0] != '\0') {
1856e91bba0SGirish Moodalbail 		if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
1866e91bba0SGirish Moodalbail 			return (B_FALSE);
1876e91bba0SGirish Moodalbail 	}
1886e91bba0SGirish Moodalbail 	if (ifname != NULL && ifname[0] != '\0') {
1896e91bba0SGirish Moodalbail 		if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
1906e91bba0SGirish Moodalbail 			return (B_FALSE);
1916e91bba0SGirish Moodalbail 	}
1926e91bba0SGirish Moodalbail 	if (aobjname != NULL && aobjname[0] != '\0') {
1936e91bba0SGirish Moodalbail 		if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
1946e91bba0SGirish Moodalbail 			return (B_FALSE);
1956e91bba0SGirish Moodalbail 	}
1966e91bba0SGirish Moodalbail 
1976e91bba0SGirish Moodalbail 	return (B_TRUE);
1986e91bba0SGirish Moodalbail }
1996e91bba0SGirish Moodalbail 
2006e91bba0SGirish Moodalbail /*
2016e91bba0SGirish Moodalbail  * Retrieves the property value from the DB. The property whose value is to be
2026e91bba0SGirish Moodalbail  * retrieved is in `pargp->ia_pname'.
2036e91bba0SGirish Moodalbail  */
2046e91bba0SGirish Moodalbail /* ARGSUSED */
2056e91bba0SGirish Moodalbail boolean_t
2066e91bba0SGirish Moodalbail ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
2076e91bba0SGirish Moodalbail     int *errp)
2086e91bba0SGirish Moodalbail {
2096e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = arg;
2106e91bba0SGirish Moodalbail 	boolean_t		cont = B_TRUE;
2116e91bba0SGirish Moodalbail 	char			*pval;
2126e91bba0SGirish Moodalbail 	int			err = 0;
2136e91bba0SGirish Moodalbail 
2146e91bba0SGirish Moodalbail 	*errp = 0;
2156e91bba0SGirish Moodalbail 
2166e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
2176e91bba0SGirish Moodalbail 	    pargp->ia_ifname, pargp->ia_aobjname))
2186e91bba0SGirish Moodalbail 		return (B_TRUE);
2196e91bba0SGirish Moodalbail 
2206e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
2216e91bba0SGirish Moodalbail 	    &pval)) == 0) {
2226e91bba0SGirish Moodalbail 		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
2236e91bba0SGirish Moodalbail 		/*
2246e91bba0SGirish Moodalbail 		 * We have retrieved what we are looking for.
2256e91bba0SGirish Moodalbail 		 * Stop the walker.
2266e91bba0SGirish Moodalbail 		 */
2276e91bba0SGirish Moodalbail 		cont = B_FALSE;
2286e91bba0SGirish Moodalbail 	} else {
2296e91bba0SGirish Moodalbail 		if (err == ENOENT)
2306e91bba0SGirish Moodalbail 			err = 0;
2316e91bba0SGirish Moodalbail 		*errp = err;
2326e91bba0SGirish Moodalbail 	}
2336e91bba0SGirish Moodalbail 
2346e91bba0SGirish Moodalbail 	return (cont);
2356e91bba0SGirish Moodalbail }
2366e91bba0SGirish Moodalbail 
2376e91bba0SGirish Moodalbail /*
2386e91bba0SGirish Moodalbail  * Removes the property value from the DB. The property whose value is to be
2396e91bba0SGirish Moodalbail  * removed is in `pargp->ia_pname'.
2406e91bba0SGirish Moodalbail  */
2416e91bba0SGirish Moodalbail /* ARGSUSED */
2426e91bba0SGirish Moodalbail boolean_t
2436e91bba0SGirish Moodalbail ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
2446e91bba0SGirish Moodalbail     int *errp)
2456e91bba0SGirish Moodalbail {
2466e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = arg;
2476e91bba0SGirish Moodalbail 
2486e91bba0SGirish Moodalbail 	*errp = 0;
2496e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
2506e91bba0SGirish Moodalbail 	    pargp->ia_ifname, pargp->ia_aobjname))
2516e91bba0SGirish Moodalbail 		return (B_TRUE);
2526e91bba0SGirish Moodalbail 
2536e91bba0SGirish Moodalbail 	if (!nvlist_exists(db_nvl, pargp->ia_pname))
2546e91bba0SGirish Moodalbail 		return (B_TRUE);
2556e91bba0SGirish Moodalbail 
2566e91bba0SGirish Moodalbail 	/*
2576e91bba0SGirish Moodalbail 	 * We found the property in the DB. If IPMGMT_REMOVE is not set then
2586e91bba0SGirish Moodalbail 	 * delete the entry from the db. If it is set, then the property is a
2596e91bba0SGirish Moodalbail 	 * multi-valued property so just remove the specified values from DB.
2606e91bba0SGirish Moodalbail 	 */
2616e91bba0SGirish Moodalbail 	if (pargp->ia_flags & IPMGMT_REMOVE) {
2626e91bba0SGirish Moodalbail 		char	*dbpval = NULL;
2636e91bba0SGirish Moodalbail 		char	*inpval = pargp->ia_pval;
2646e91bba0SGirish Moodalbail 		char	pval[MAXPROPVALLEN];
2656e91bba0SGirish Moodalbail 		char	*val, *lasts;
2666e91bba0SGirish Moodalbail 
2676e91bba0SGirish Moodalbail 		*errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
2686e91bba0SGirish Moodalbail 		if (*errp != 0)
2696e91bba0SGirish Moodalbail 			return (B_FALSE);
2706e91bba0SGirish Moodalbail 
2716e91bba0SGirish Moodalbail 		/*
2726e91bba0SGirish Moodalbail 		 * multi-valued properties are represented as comma separated
2736e91bba0SGirish Moodalbail 		 * values. Use string tokenizer functions to split them and
2746e91bba0SGirish Moodalbail 		 * search for the value to be removed.
2756e91bba0SGirish Moodalbail 		 */
2766e91bba0SGirish Moodalbail 		bzero(pval, sizeof (pval));
2776e91bba0SGirish Moodalbail 		if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
2786e91bba0SGirish Moodalbail 			if (strcmp(val, inpval) != 0)
2796e91bba0SGirish Moodalbail 				(void) strlcat(pval, val, MAXPROPVALLEN);
2806e91bba0SGirish Moodalbail 			while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
2816e91bba0SGirish Moodalbail 				if (strcmp(val, inpval) != 0) {
2826e91bba0SGirish Moodalbail 					if (pval[0] != '\0')
2836e91bba0SGirish Moodalbail 						(void) strlcat(pval, ",",
2846e91bba0SGirish Moodalbail 						    MAXPROPVALLEN);
2856e91bba0SGirish Moodalbail 					(void) strlcat(pval, val,
2866e91bba0SGirish Moodalbail 					    MAXPROPVALLEN);
2876e91bba0SGirish Moodalbail 				}
2886e91bba0SGirish Moodalbail 			}
2896e91bba0SGirish Moodalbail 		} else {
2906e91bba0SGirish Moodalbail 			if (strcmp(dbpval, inpval) != 0)
2916e91bba0SGirish Moodalbail 				*errp = ENOENT;
2926e91bba0SGirish Moodalbail 			else
2936e91bba0SGirish Moodalbail 				buf[0] =  '\0';
2946e91bba0SGirish Moodalbail 			return (B_FALSE);
2956e91bba0SGirish Moodalbail 		}
2966e91bba0SGirish Moodalbail 		*errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
2976e91bba0SGirish Moodalbail 		if (*errp != 0)
2986e91bba0SGirish Moodalbail 			return (B_FALSE);
2996e91bba0SGirish Moodalbail 
3006e91bba0SGirish Moodalbail 		(void) memset(buf, 0, buflen);
3016e91bba0SGirish Moodalbail 		if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
3026e91bba0SGirish Moodalbail 			/* buffer overflow */
3036e91bba0SGirish Moodalbail 			*errp = ENOBUFS;
3046e91bba0SGirish Moodalbail 		}
3056e91bba0SGirish Moodalbail 	} else {
3066e91bba0SGirish Moodalbail 		buf[0] = '\0';
3076e91bba0SGirish Moodalbail 	}
3086e91bba0SGirish Moodalbail 
3096e91bba0SGirish Moodalbail 	/* stop the search */
3106e91bba0SGirish Moodalbail 	return (B_FALSE);
3116e91bba0SGirish Moodalbail }
3126e91bba0SGirish Moodalbail 
3136e91bba0SGirish Moodalbail /*
3146e91bba0SGirish Moodalbail  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
3156e91bba0SGirish Moodalbail  * found, when one of the following occurs first.
3166e91bba0SGirish Moodalbail  * - the input aobjname matches the db aobjname. Return the db address.
3176e91bba0SGirish Moodalbail  * - the input interface matches the db interface. Return all the
3186e91bba0SGirish Moodalbail  *   matching db lines with addresses.
3196e91bba0SGirish Moodalbail  */
3206e91bba0SGirish Moodalbail /* ARGSUSED */
3216e91bba0SGirish Moodalbail boolean_t
3226e91bba0SGirish Moodalbail ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
3236e91bba0SGirish Moodalbail     int *errp)
3246e91bba0SGirish Moodalbail {
3256e91bba0SGirish Moodalbail 	ipmgmt_getaddr_cbarg_t	*cbarg = arg;
3266e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
3276e91bba0SGirish Moodalbail 	char		*db_ifname = NULL;
3286e91bba0SGirish Moodalbail 	nvlist_t	*db_addr = NULL;
3296e91bba0SGirish Moodalbail 	char		name[IPMGMT_STRSIZE];
3306e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
3316e91bba0SGirish Moodalbail 	boolean_t	add_nvl = B_FALSE;
3326e91bba0SGirish Moodalbail 
3336e91bba0SGirish Moodalbail 	/* Parse db nvlist */
3346e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
3356e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
3366e91bba0SGirish Moodalbail 		if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
3376e91bba0SGirish Moodalbail 			(void) nvpair_value_nvlist(nvp, &db_addr);
3386e91bba0SGirish Moodalbail 		else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
3396e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
3406e91bba0SGirish Moodalbail 		else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
3416e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
3426e91bba0SGirish Moodalbail 	}
3436e91bba0SGirish Moodalbail 
3446e91bba0SGirish Moodalbail 	if (db_aobjname == NULL) /* Not an address */
3456e91bba0SGirish Moodalbail 		return (B_TRUE);
3466e91bba0SGirish Moodalbail 
3476e91bba0SGirish Moodalbail 	/* Check for a match between the aobjnames or the interface name */
3486e91bba0SGirish Moodalbail 	if (cbarg->cb_aobjname[0] != '\0') {
3496e91bba0SGirish Moodalbail 		if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
3506e91bba0SGirish Moodalbail 			add_nvl = B_TRUE;
3516e91bba0SGirish Moodalbail 	} else if (cbarg->cb_ifname[0] != '\0') {
3526e91bba0SGirish Moodalbail 		if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
3536e91bba0SGirish Moodalbail 			add_nvl = B_TRUE;
3546e91bba0SGirish Moodalbail 	} else {
3556e91bba0SGirish Moodalbail 		add_nvl = B_TRUE;
3566e91bba0SGirish Moodalbail 	}
3576e91bba0SGirish Moodalbail 
3586e91bba0SGirish Moodalbail 	if (add_nvl) {
3596e91bba0SGirish Moodalbail 		(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
3606e91bba0SGirish Moodalbail 		    cbarg->cb_ocnt);
3616e91bba0SGirish Moodalbail 		*errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
3626e91bba0SGirish Moodalbail 		if (*errp == 0)
3636e91bba0SGirish Moodalbail 			cbarg->cb_ocnt++;
3646e91bba0SGirish Moodalbail 	}
3656e91bba0SGirish Moodalbail 	return (B_TRUE);
3666e91bba0SGirish Moodalbail }
3676e91bba0SGirish Moodalbail 
3686e91bba0SGirish Moodalbail /*
3699b5bf10aSMark Haywood  * This function only gets called if a volatile filesystem version
3709b5bf10aSMark Haywood  * of the configuration file has been created. This only happens in the
3719b5bf10aSMark Haywood  * extremely rare case that a request has been made to update the configuration
3729b5bf10aSMark Haywood  * file at boottime while the root filesystem was read-only. This is
3739b5bf10aSMark Haywood  * really a rare occurrence now that we don't support UFS root filesystems
3749b5bf10aSMark Haywood  * any longer. This function will periodically attempt to write the
3759b5bf10aSMark Haywood  * configuration back to its location on the root filesystem. Success
3769b5bf10aSMark Haywood  * will indicate that the filesystem is no longer read-only.
3779b5bf10aSMark Haywood  */
3789b5bf10aSMark Haywood /* ARGSUSED */
3799b5bf10aSMark Haywood static void *
3809b5bf10aSMark Haywood ipmgmt_db_restore_thread(void *arg)
3819b5bf10aSMark Haywood {
3829b5bf10aSMark Haywood 	int err;
3839b5bf10aSMark Haywood 
3849b5bf10aSMark Haywood 	for (;;) {
3859b5bf10aSMark Haywood 		(void) sleep(5);
3869b5bf10aSMark Haywood 		(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
3879b5bf10aSMark Haywood 		if (!ipmgmt_rdonly_root)
3889b5bf10aSMark Haywood 			break;
3899b5bf10aSMark Haywood 		err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
3909b5bf10aSMark Haywood 		if (err == 0) {
3919b5bf10aSMark Haywood 			ipmgmt_rdonly_root = B_FALSE;
3929b5bf10aSMark Haywood 			break;
3939b5bf10aSMark Haywood 		}
3949b5bf10aSMark Haywood 		(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
3959b5bf10aSMark Haywood 	}
3969b5bf10aSMark Haywood 	(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
3979b5bf10aSMark Haywood 	return (NULL);
3989b5bf10aSMark Haywood }
3999b5bf10aSMark Haywood 
4009b5bf10aSMark Haywood /*
4016e91bba0SGirish Moodalbail  * This function takes the appropriate lock, read or write, based on the
4029b5bf10aSMark Haywood  * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
4039b5bf10aSMark Haywood  * by the fact that we are not always guaranteed to have a writable root
4049b5bf10aSMark Haywood  * filesystem since it is possible that we are reading or writing during
4059b5bf10aSMark Haywood  * bootime while the root filesystem is still read-only. This is, by far,
4069b5bf10aSMark Haywood  * the exception case. Normally, this function will be called when the
4079b5bf10aSMark Haywood  * root filesystem is writable. In the unusual case where this is not
4089b5bf10aSMark Haywood  * true, the configuration file is copied to the volatile file system
4099b5bf10aSMark Haywood  * and is updated there until the root filesystem becomes writable. At
4109b5bf10aSMark Haywood  * that time the file will be moved back to its proper location by
4119b5bf10aSMark Haywood  * ipmgmt_db_restore_thread().
4126e91bba0SGirish Moodalbail  */
4136e91bba0SGirish Moodalbail extern int
4146e91bba0SGirish Moodalbail ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
4156e91bba0SGirish Moodalbail {
4166e91bba0SGirish Moodalbail 	int		err;
4176e91bba0SGirish Moodalbail 	boolean_t	writeop;
4186e91bba0SGirish Moodalbail 	mode_t		mode;
4199b5bf10aSMark Haywood 	pthread_t	tid;
420*8887b57dSGirish Moodalbail 	pthread_attr_t	attr;
4216e91bba0SGirish Moodalbail 
4226e91bba0SGirish Moodalbail 	writeop = (db_op != IPADM_DB_READ);
4236e91bba0SGirish Moodalbail 	if (writeop) {
4246e91bba0SGirish Moodalbail 		(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
4256e91bba0SGirish Moodalbail 		mode = IPADM_FILE_MODE;
4266e91bba0SGirish Moodalbail 	} else {
4276e91bba0SGirish Moodalbail 		(void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
4286e91bba0SGirish Moodalbail 		mode = 0;
4296e91bba0SGirish Moodalbail 	}
4306e91bba0SGirish Moodalbail 
4319b5bf10aSMark Haywood 	/*
4329b5bf10aSMark Haywood 	 * Did a previous write attempt fail? If so, don't even try to
4339b5bf10aSMark Haywood 	 * read/write to IPADM_DB_FILE.
4349b5bf10aSMark Haywood 	 */
4359b5bf10aSMark Haywood 	if (!ipmgmt_rdonly_root) {
4369b5bf10aSMark Haywood 		err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
4379b5bf10aSMark Haywood 		    mode, db_op);
4389b5bf10aSMark Haywood 		if (err != EROFS)
4399b5bf10aSMark Haywood 			goto done;
4409b5bf10aSMark Haywood 	}
4419b5bf10aSMark Haywood 
4429b5bf10aSMark Haywood 	/*
4439b5bf10aSMark Haywood 	 * If we haven't already copied the file to the volatile
4449b5bf10aSMark Haywood 	 * file system, do so. This should only happen on a failed
4459b5bf10aSMark Haywood 	 * writeop(i.e., we have acquired the write lock above).
4469b5bf10aSMark Haywood 	 */
4479b5bf10aSMark Haywood 	if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
4489b5bf10aSMark Haywood 		assert(writeop);
4499b5bf10aSMark Haywood 		err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
4509b5bf10aSMark Haywood 		if (err != 0)
4519b5bf10aSMark Haywood 			goto done;
452*8887b57dSGirish Moodalbail 		(void) pthread_attr_init(&attr);
453*8887b57dSGirish Moodalbail 		(void) pthread_attr_setdetachstate(&attr,
454*8887b57dSGirish Moodalbail 		    PTHREAD_CREATE_DETACHED);
455*8887b57dSGirish Moodalbail 		err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
4569b5bf10aSMark Haywood 		    NULL);
457*8887b57dSGirish Moodalbail 		(void) pthread_attr_destroy(&attr);
4589b5bf10aSMark Haywood 		if (err != 0) {
4599b5bf10aSMark Haywood 			(void) unlink(IPADM_VOL_DB_FILE);
4609b5bf10aSMark Haywood 			goto done;
4619b5bf10aSMark Haywood 		}
4629b5bf10aSMark Haywood 		ipmgmt_rdonly_root = B_TRUE;
4639b5bf10aSMark Haywood 	}
4649b5bf10aSMark Haywood 
4659b5bf10aSMark Haywood 	/*
4669b5bf10aSMark Haywood 	 * Read/write from the volatile copy.
4679b5bf10aSMark Haywood 	 */
4689b5bf10aSMark Haywood 	err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
4699b5bf10aSMark Haywood 	    mode, db_op);
4709b5bf10aSMark Haywood done:
4716e91bba0SGirish Moodalbail 	(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
4726e91bba0SGirish Moodalbail 	return (err);
4736e91bba0SGirish Moodalbail }
4746e91bba0SGirish Moodalbail 
4756e91bba0SGirish Moodalbail /*
4766e91bba0SGirish Moodalbail  * Used to add an entry towards the end of DB. It just returns B_TRUE for
4776e91bba0SGirish Moodalbail  * every line of the DB. When we reach the end, ipadm_rw_db() adds the
4786e91bba0SGirish Moodalbail  * line at the end.
4796e91bba0SGirish Moodalbail  */
4806e91bba0SGirish Moodalbail /* ARGSUSED */
4816e91bba0SGirish Moodalbail boolean_t
4826e91bba0SGirish Moodalbail ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
4836e91bba0SGirish Moodalbail {
4846e91bba0SGirish Moodalbail 	return (B_TRUE);
4856e91bba0SGirish Moodalbail }
4866e91bba0SGirish Moodalbail 
4876e91bba0SGirish Moodalbail /*
4886e91bba0SGirish Moodalbail  * This function is used to update or create an entry in DB. The nvlist_t,
4896e91bba0SGirish Moodalbail  * `in_nvl', represents the line we are looking for. Once we ensure the right
4906e91bba0SGirish Moodalbail  * line from DB, we update that entry.
4916e91bba0SGirish Moodalbail  */
4926e91bba0SGirish Moodalbail boolean_t
4936e91bba0SGirish Moodalbail ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
4946e91bba0SGirish Moodalbail     int *errp)
4956e91bba0SGirish Moodalbail {
4966e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	*cb = arg;
4976e91bba0SGirish Moodalbail 	uint_t			flags = cb->dbw_flags;
4986e91bba0SGirish Moodalbail 	nvlist_t		*in_nvl = cb->dbw_nvl;
4996e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
5006e91bba0SGirish Moodalbail 	char			*name, *instrval = NULL, *dbstrval = NULL;
5016e91bba0SGirish Moodalbail 	char			pval[MAXPROPVALLEN];
5026e91bba0SGirish Moodalbail 
503*8887b57dSGirish Moodalbail 	*errp = 0;
5046e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
5056e91bba0SGirish Moodalbail 		return (B_TRUE);
5066e91bba0SGirish Moodalbail 
5076e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
5086e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
5096e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
5106e91bba0SGirish Moodalbail 		if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
5116e91bba0SGirish Moodalbail 			break;
5126e91bba0SGirish Moodalbail 	}
5136e91bba0SGirish Moodalbail 
5146e91bba0SGirish Moodalbail 	if (nvp == NULL)
5156e91bba0SGirish Moodalbail 		return (B_TRUE);
5166e91bba0SGirish Moodalbail 
5176e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
5186e91bba0SGirish Moodalbail 
5196e91bba0SGirish Moodalbail 	if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
5206e91bba0SGirish Moodalbail 		return (B_FALSE);
5216e91bba0SGirish Moodalbail 
5226e91bba0SGirish Moodalbail 	/*
5236e91bba0SGirish Moodalbail 	 * If IPMGMT_APPEND is set then we are dealing with multi-valued
5246e91bba0SGirish Moodalbail 	 * properties. We append to the entry from the db, with the new value.
5256e91bba0SGirish Moodalbail 	 */
5266e91bba0SGirish Moodalbail 	if (flags & IPMGMT_APPEND) {
5276e91bba0SGirish Moodalbail 		if ((*errp = nvlist_lookup_string(db_nvl, name,
5286e91bba0SGirish Moodalbail 		    &dbstrval)) != 0)
5296e91bba0SGirish Moodalbail 			return (B_FALSE);
5306e91bba0SGirish Moodalbail 		(void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
5316e91bba0SGirish Moodalbail 		    instrval);
5326e91bba0SGirish Moodalbail 		if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
5336e91bba0SGirish Moodalbail 			return (B_FALSE);
5346e91bba0SGirish Moodalbail 	} else {
5356e91bba0SGirish Moodalbail 		/* case	of in-line update of a db entry */
5366e91bba0SGirish Moodalbail 		if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
5376e91bba0SGirish Moodalbail 			return (B_FALSE);
5386e91bba0SGirish Moodalbail 	}
5396e91bba0SGirish Moodalbail 
5406e91bba0SGirish Moodalbail 	(void) memset(buf, 0, buflen);
5416e91bba0SGirish Moodalbail 	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
5426e91bba0SGirish Moodalbail 		/* buffer overflow */
5436e91bba0SGirish Moodalbail 		*errp = ENOBUFS;
5446e91bba0SGirish Moodalbail 	}
5456e91bba0SGirish Moodalbail 
5466e91bba0SGirish Moodalbail 	/* we updated the DB entry, so do not continue */
5476e91bba0SGirish Moodalbail 	return (B_FALSE);
5486e91bba0SGirish Moodalbail }
5496e91bba0SGirish Moodalbail 
5506e91bba0SGirish Moodalbail /*
5516e91bba0SGirish Moodalbail  * For the given `cbarg->cb_ifname' interface, retrieves any persistent
5526e91bba0SGirish Moodalbail  * interface information (used in 'ipadm show-if')
5536e91bba0SGirish Moodalbail  */
5546e91bba0SGirish Moodalbail /* ARGSUSED */
5556e91bba0SGirish Moodalbail boolean_t
5566e91bba0SGirish Moodalbail ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
5576e91bba0SGirish Moodalbail     int *errp)
5586e91bba0SGirish Moodalbail {
5596e91bba0SGirish Moodalbail 	ipmgmt_getif_cbarg_t	*cbarg = arg;
5606e91bba0SGirish Moodalbail 	char			*ifname = cbarg->cb_ifname;
5616e91bba0SGirish Moodalbail 	char			*intf = NULL;
5626e91bba0SGirish Moodalbail 	ipadm_if_info_t		*ifp = NULL;
5636e91bba0SGirish Moodalbail 	sa_family_t		af;
5646e91bba0SGirish Moodalbail 	char			*afstr;
5656e91bba0SGirish Moodalbail 
5666e91bba0SGirish Moodalbail 	*errp = 0;
5676e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
5686e91bba0SGirish Moodalbail 	    nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
5696e91bba0SGirish Moodalbail 	    (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
5706e91bba0SGirish Moodalbail 		return (B_TRUE);
5716e91bba0SGirish Moodalbail 	}
5726e91bba0SGirish Moodalbail 	af = atoi(afstr);
5736e91bba0SGirish Moodalbail 	for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
5746e91bba0SGirish Moodalbail 		if (strcmp(ifp->ifi_name, intf) == 0)
5756e91bba0SGirish Moodalbail 			break;
5766e91bba0SGirish Moodalbail 	}
5776e91bba0SGirish Moodalbail 	if (ifp == NULL) {
5786e91bba0SGirish Moodalbail 		ipadm_if_info_t *new;
5796e91bba0SGirish Moodalbail 
5806e91bba0SGirish Moodalbail 		if ((new = calloc(1, sizeof (*new))) == NULL) {
5816e91bba0SGirish Moodalbail 			*errp = ENOMEM;
5826e91bba0SGirish Moodalbail 			return (B_FALSE); /* don't continue the walk */
5836e91bba0SGirish Moodalbail 		}
5846e91bba0SGirish Moodalbail 		new->ifi_next = cbarg->cb_ifinfo;
5856e91bba0SGirish Moodalbail 		cbarg->cb_ifinfo = new;
5866e91bba0SGirish Moodalbail 		ifp = new;
5876e91bba0SGirish Moodalbail 		(void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
5886e91bba0SGirish Moodalbail 	}
5896e91bba0SGirish Moodalbail 
5906e91bba0SGirish Moodalbail 	if (af == AF_INET) {
5916e91bba0SGirish Moodalbail 		ifp->ifi_pflags |= IFIF_IPV4;
5926e91bba0SGirish Moodalbail 	} else {
5936e91bba0SGirish Moodalbail 		assert(af == AF_INET6);
5946e91bba0SGirish Moodalbail 		ifp->ifi_pflags |= IFIF_IPV6;
5956e91bba0SGirish Moodalbail 	}
5966e91bba0SGirish Moodalbail 
5976e91bba0SGirish Moodalbail 	/* Terminate the walk if we found both v4 and v6 interfaces. */
5986e91bba0SGirish Moodalbail 	if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
5996e91bba0SGirish Moodalbail 	    (ifp->ifi_pflags & IFIF_IPV6))
6006e91bba0SGirish Moodalbail 		return (B_FALSE);
6016e91bba0SGirish Moodalbail 
6026e91bba0SGirish Moodalbail 	return (B_TRUE);
6036e91bba0SGirish Moodalbail }
6046e91bba0SGirish Moodalbail 
6056e91bba0SGirish Moodalbail /*
6066e91bba0SGirish Moodalbail  * Deletes those entries from the database for which interface name
6076e91bba0SGirish Moodalbail  * matches with the given `cbarg->cb_ifname'
6086e91bba0SGirish Moodalbail  */
6096e91bba0SGirish Moodalbail /* ARGSUSED */
6106e91bba0SGirish Moodalbail boolean_t
6116e91bba0SGirish Moodalbail ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
6126e91bba0SGirish Moodalbail     int *errp)
6136e91bba0SGirish Moodalbail {
6146e91bba0SGirish Moodalbail 	ipmgmt_if_cbarg_t *cbarg = arg;
6156e91bba0SGirish Moodalbail 	boolean_t	isv6 = (cbarg->cb_family == AF_INET6);
6166e91bba0SGirish Moodalbail 	char		*ifname = cbarg->cb_ifname;
6176e91bba0SGirish Moodalbail 	char		*modstr = NULL;
6186e91bba0SGirish Moodalbail 	char		*afstr;
6196e91bba0SGirish Moodalbail 	char		*aobjname;
6206e91bba0SGirish Moodalbail 	uint_t		proto;
6216e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t *head;
6226e91bba0SGirish Moodalbail 	boolean_t	aobjfound = B_FALSE;
6236e91bba0SGirish Moodalbail 
6246e91bba0SGirish Moodalbail 	*errp = 0;
6256e91bba0SGirish Moodalbail 
6266e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
6276e91bba0SGirish Moodalbail 		return (B_TRUE);
6286e91bba0SGirish Moodalbail 
6296e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
6306e91bba0SGirish Moodalbail 		if (atoi(afstr) == cbarg->cb_family)
6316e91bba0SGirish Moodalbail 			goto delete;
6326e91bba0SGirish Moodalbail 		return (B_TRUE);
6336e91bba0SGirish Moodalbail 	}
6346e91bba0SGirish Moodalbail 
6356e91bba0SGirish Moodalbail 	/* Reset all the interface configurations for 'ifname' */
6366e91bba0SGirish Moodalbail 	if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
6376e91bba0SGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
6386e91bba0SGirish Moodalbail 		goto delete;
6396e91bba0SGirish Moodalbail 	}
6406e91bba0SGirish Moodalbail 	if (!isv6 &&
6416e91bba0SGirish Moodalbail 	    (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
6426e91bba0SGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
6436e91bba0SGirish Moodalbail 		goto delete;
6446e91bba0SGirish Moodalbail 	}
6456e91bba0SGirish Moodalbail 
6466e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
6476e91bba0SGirish Moodalbail 		/*
6486e91bba0SGirish Moodalbail 		 * This must be an address property. Delete this
6496e91bba0SGirish Moodalbail 		 * line if there is a match in the address family.
6506e91bba0SGirish Moodalbail 		 */
6516e91bba0SGirish Moodalbail 		head = aobjmap.aobjmap_head;
6526e91bba0SGirish Moodalbail 		while (head != NULL) {
6536e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname, aobjname) == 0) {
6546e91bba0SGirish Moodalbail 				aobjfound = B_TRUE;
6556e91bba0SGirish Moodalbail 				if (head->am_family == cbarg->cb_family)
6566e91bba0SGirish Moodalbail 					goto delete;
6576e91bba0SGirish Moodalbail 			}
6586e91bba0SGirish Moodalbail 			head = head->am_next;
6596e91bba0SGirish Moodalbail 		}
6606e91bba0SGirish Moodalbail 		/*
6616e91bba0SGirish Moodalbail 		 * If aobjfound = B_FALSE, then this address is not
6626e91bba0SGirish Moodalbail 		 * available in active configuration. We should go ahead
6636e91bba0SGirish Moodalbail 		 * and delete it.
6646e91bba0SGirish Moodalbail 		 */
6656e91bba0SGirish Moodalbail 		if (!aobjfound)
6666e91bba0SGirish Moodalbail 			goto delete;
6676e91bba0SGirish Moodalbail 	}
6686e91bba0SGirish Moodalbail 
6696e91bba0SGirish Moodalbail 	/*
6706e91bba0SGirish Moodalbail 	 * If we are removing both v4 and v6 interface, then we get rid of
6716e91bba0SGirish Moodalbail 	 * all the properties for that interface. On the other hand, if we
6726e91bba0SGirish Moodalbail 	 * are deleting only v4 instance of an interface, then we delete v4
6736e91bba0SGirish Moodalbail 	 * properties only.
6746e91bba0SGirish Moodalbail 	 */
6756e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
6766e91bba0SGirish Moodalbail 		proto = ipadm_str2proto(modstr);
6776e91bba0SGirish Moodalbail 		switch (proto) {
6786e91bba0SGirish Moodalbail 		case MOD_PROTO_IPV6:
6796e91bba0SGirish Moodalbail 			if (isv6)
6806e91bba0SGirish Moodalbail 				goto delete;
6816e91bba0SGirish Moodalbail 			break;
6826e91bba0SGirish Moodalbail 		case MOD_PROTO_IPV4:
6836e91bba0SGirish Moodalbail 			if (!isv6)
6846e91bba0SGirish Moodalbail 				goto delete;
6856e91bba0SGirish Moodalbail 			break;
6866e91bba0SGirish Moodalbail 		case MOD_PROTO_IP:
6876e91bba0SGirish Moodalbail 			/* this should never be the case, today */
6886e91bba0SGirish Moodalbail 			assert(0);
6896e91bba0SGirish Moodalbail 			break;
6906e91bba0SGirish Moodalbail 		}
6916e91bba0SGirish Moodalbail 	}
6926e91bba0SGirish Moodalbail 	/* Not found a match yet. Continue processing the db */
6936e91bba0SGirish Moodalbail 	return (B_TRUE);
6946e91bba0SGirish Moodalbail delete:
6956e91bba0SGirish Moodalbail 	/* delete the line from the db */
6966e91bba0SGirish Moodalbail 	buf[0] = '\0';
6976e91bba0SGirish Moodalbail 	return (B_TRUE);
6986e91bba0SGirish Moodalbail }
6996e91bba0SGirish Moodalbail 
7006e91bba0SGirish Moodalbail /*
7016e91bba0SGirish Moodalbail  * Deletes those entries from the database for which address object name
7026e91bba0SGirish Moodalbail  * matches with the given `cbarg->cb_aobjname'
7036e91bba0SGirish Moodalbail  */
7046e91bba0SGirish Moodalbail /* ARGSUSED */
7056e91bba0SGirish Moodalbail boolean_t
7066e91bba0SGirish Moodalbail ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
7076e91bba0SGirish Moodalbail     int *errp)
7086e91bba0SGirish Moodalbail {
7096e91bba0SGirish Moodalbail 	ipmgmt_resetaddr_cbarg_t *cbarg = arg;
7106e91bba0SGirish Moodalbail 	char		*aobjname = cbarg->cb_aobjname;
7116e91bba0SGirish Moodalbail 
7126e91bba0SGirish Moodalbail 	*errp = 0;
7136e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
7146e91bba0SGirish Moodalbail 		return (B_TRUE);
7156e91bba0SGirish Moodalbail 
7166e91bba0SGirish Moodalbail 	/* delete the line from the db */
7176e91bba0SGirish Moodalbail 	buf[0] = '\0';
7186e91bba0SGirish Moodalbail 	return (B_TRUE);
7196e91bba0SGirish Moodalbail }
7206e91bba0SGirish Moodalbail 
7216e91bba0SGirish Moodalbail /*
7226e91bba0SGirish Moodalbail  * Retrieves all interface props, including addresses, for given interface(s).
7236e91bba0SGirish Moodalbail  * `invl' contains the list of interfaces, for which information need to be
7246e91bba0SGirish Moodalbail  * retrieved.
7256e91bba0SGirish Moodalbail  */
7266e91bba0SGirish Moodalbail /* ARGSUSED */
7276e91bba0SGirish Moodalbail boolean_t
7286e91bba0SGirish Moodalbail ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
7296e91bba0SGirish Moodalbail     int *errp)
7306e91bba0SGirish Moodalbail {
7316e91bba0SGirish Moodalbail 	ipmgmt_initif_cbarg_t	*cbarg = arg;
7326e91bba0SGirish Moodalbail 	nvlist_t		*onvl = cbarg->cb_onvl;
7336e91bba0SGirish Moodalbail 	nvlist_t		*invl = cbarg->cb_invl;
7346e91bba0SGirish Moodalbail 	sa_family_t		in_af = cbarg->cb_family;
7356e91bba0SGirish Moodalbail 	char			*db_ifname;
7366e91bba0SGirish Moodalbail 
7376e91bba0SGirish Moodalbail 	*errp = 0;
7386e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
7396e91bba0SGirish Moodalbail 	    nvlist_exists(invl, db_ifname)) {
7406e91bba0SGirish Moodalbail 		char		name[IPMGMT_STRSIZE];
7416e91bba0SGirish Moodalbail 		sa_family_t	db_af = in_af;
7426e91bba0SGirish Moodalbail 		uint_t		proto;
7436e91bba0SGirish Moodalbail 		char		*pstr;
7446e91bba0SGirish Moodalbail 
7456e91bba0SGirish Moodalbail 		if (in_af != AF_UNSPEC) {
7466e91bba0SGirish Moodalbail 			if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
7476e91bba0SGirish Moodalbail 			    &pstr) == 0) {
7486e91bba0SGirish Moodalbail 				proto = ipadm_str2proto(pstr);
7496e91bba0SGirish Moodalbail 				if (proto == MOD_PROTO_IPV4)
7506e91bba0SGirish Moodalbail 					db_af = AF_INET;
7516e91bba0SGirish Moodalbail 				else if (proto == MOD_PROTO_IPV6)
7526e91bba0SGirish Moodalbail 					db_af = AF_INET6;
7536e91bba0SGirish Moodalbail 				else
7546e91bba0SGirish Moodalbail 					db_af = in_af;
7556e91bba0SGirish Moodalbail 			} else {
7566e91bba0SGirish Moodalbail 				if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
7576e91bba0SGirish Moodalbail 				    nvlist_exists(db_nvl, IPADM_NVP_DHCP))
7586e91bba0SGirish Moodalbail 					db_af = AF_INET;
7596e91bba0SGirish Moodalbail 				else
7606e91bba0SGirish Moodalbail 					db_af = AF_INET6;
7616e91bba0SGirish Moodalbail 			}
7626e91bba0SGirish Moodalbail 		}
7636e91bba0SGirish Moodalbail 		if (in_af == db_af) {
7646e91bba0SGirish Moodalbail 			(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
7656e91bba0SGirish Moodalbail 			    cbarg->cb_ocnt);
7666e91bba0SGirish Moodalbail 			*errp = nvlist_add_nvlist(onvl, name, db_nvl);
7676e91bba0SGirish Moodalbail 			if (*errp == 0)
7686e91bba0SGirish Moodalbail 				cbarg->cb_ocnt++;
7696e91bba0SGirish Moodalbail 		}
7706e91bba0SGirish Moodalbail 	}
7716e91bba0SGirish Moodalbail 	return (B_TRUE);
7726e91bba0SGirish Moodalbail }
7736e91bba0SGirish Moodalbail 
7746e91bba0SGirish Moodalbail /*
7756e91bba0SGirish Moodalbail  * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
7766e91bba0SGirish Moodalbail  * into `aobjmap' structure.
7776e91bba0SGirish Moodalbail  */
7786e91bba0SGirish Moodalbail static int
7796e91bba0SGirish Moodalbail i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
7806e91bba0SGirish Moodalbail {
7816e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*new, *head;
7826e91bba0SGirish Moodalbail 
7836e91bba0SGirish Moodalbail 	head = aobjmap.aobjmap_head;
7846e91bba0SGirish Moodalbail 	if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
7856e91bba0SGirish Moodalbail 		return (ENOMEM);
7866e91bba0SGirish Moodalbail 	*new = *nodep;
7876e91bba0SGirish Moodalbail 	new->am_next = NULL;
7886e91bba0SGirish Moodalbail 
7896e91bba0SGirish Moodalbail 	/* Add the node at the beginning of the list */
7906e91bba0SGirish Moodalbail 	if (head == NULL) {
7916e91bba0SGirish Moodalbail 		aobjmap.aobjmap_head = new;
7926e91bba0SGirish Moodalbail 	} else {
7936e91bba0SGirish Moodalbail 		new->am_next = aobjmap.aobjmap_head;
7946e91bba0SGirish Moodalbail 		aobjmap.aobjmap_head = new;
7956e91bba0SGirish Moodalbail 	}
7966e91bba0SGirish Moodalbail 	return (0);
7976e91bba0SGirish Moodalbail }
7986e91bba0SGirish Moodalbail 
7996e91bba0SGirish Moodalbail /*
8006e91bba0SGirish Moodalbail  * A recursive function to generate alphabetized number given a decimal number.
8016e91bba0SGirish Moodalbail  * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
8026e91bba0SGirish Moodalbail  * 'ab', 'ac', et al.
8036e91bba0SGirish Moodalbail  */
8046e91bba0SGirish Moodalbail static void
8056e91bba0SGirish Moodalbail i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
8066e91bba0SGirish Moodalbail {
8076e91bba0SGirish Moodalbail 	if (num >= 26)
8086e91bba0SGirish Moodalbail 		i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
8096e91bba0SGirish Moodalbail 	if (*cp != endp) {
8106e91bba0SGirish Moodalbail 		*cp[0] = 'a' + (num % 26);
8116e91bba0SGirish Moodalbail 		(*cp)++;
8126e91bba0SGirish Moodalbail 	}
8136e91bba0SGirish Moodalbail }
8146e91bba0SGirish Moodalbail 
8156e91bba0SGirish Moodalbail /*
8166e91bba0SGirish Moodalbail  * This function generates an `aobjname', when required, and then does
8176e91bba0SGirish Moodalbail  * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
8186e91bba0SGirish Moodalbail  * through the `aobjmap' to check if an address object with the same
8196e91bba0SGirish Moodalbail  * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
8206e91bba0SGirish Moodalbail  * `aobjname's are not allowed.
8216e91bba0SGirish Moodalbail  *
8226e91bba0SGirish Moodalbail  * If `nodep->am_aobjname' is an empty string then the daemon generates an
8236e91bba0SGirish Moodalbail  * `aobjname' using the `am_nextnum', which contains the next number to be
8246e91bba0SGirish Moodalbail  * used to generate `aobjname'. `am_nextnum' is converted to base26 using
8256e91bba0SGirish Moodalbail  * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
8266e91bba0SGirish Moodalbail  *
8276e91bba0SGirish Moodalbail  * `am_nextnum' will be 0 to begin with. Every time an address object that
8286e91bba0SGirish Moodalbail  * needs `aobjname' is added it's incremented by 1. So for the first address
8296e91bba0SGirish Moodalbail  * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
8306e91bba0SGirish Moodalbail  * For the second address object on that interface `am_aobjname' will be net0/_b
8316e91bba0SGirish Moodalbail  * and  `am_nextnum' will incremented to 2.
8326e91bba0SGirish Moodalbail  */
8336e91bba0SGirish Moodalbail static int
8346e91bba0SGirish Moodalbail i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
8356e91bba0SGirish Moodalbail {
8366e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*head;
8376e91bba0SGirish Moodalbail 	uint32_t		nextnum;
8386e91bba0SGirish Moodalbail 
8396e91bba0SGirish Moodalbail 	for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
8406e91bba0SGirish Moodalbail 		if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
8416e91bba0SGirish Moodalbail 			break;
8426e91bba0SGirish Moodalbail 	nextnum = (head == NULL ? 0 : head->am_nextnum);
8436e91bba0SGirish Moodalbail 
8446e91bba0SGirish Moodalbail 	/*
8456e91bba0SGirish Moodalbail 	 * if `aobjname' is empty, then the daemon has to generate the
8466e91bba0SGirish Moodalbail 	 * next `aobjname' for the given interface and family.
8476e91bba0SGirish Moodalbail 	 */
8486e91bba0SGirish Moodalbail 	if (nodep->am_aobjname[0] == '\0') {
8496e91bba0SGirish Moodalbail 		char tmpstr[IPADM_AOBJ_USTRSIZ - 1];  /* 1 for leading  '_' */
8506e91bba0SGirish Moodalbail 		char *cp = tmpstr;
8516e91bba0SGirish Moodalbail 		char *endp = tmpstr + sizeof (tmpstr);
8526e91bba0SGirish Moodalbail 
8536e91bba0SGirish Moodalbail 		i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
8546e91bba0SGirish Moodalbail 
8556e91bba0SGirish Moodalbail 		if (cp == endp)
8566e91bba0SGirish Moodalbail 			return (EINVAL);
8576e91bba0SGirish Moodalbail 		cp[0] = '\0';
8586e91bba0SGirish Moodalbail 
8596e91bba0SGirish Moodalbail 		if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
8606e91bba0SGirish Moodalbail 		    nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
8616e91bba0SGirish Moodalbail 			return (EINVAL);
8626e91bba0SGirish Moodalbail 		}
8636e91bba0SGirish Moodalbail 		nodep->am_nextnum = ++nextnum;
8646e91bba0SGirish Moodalbail 	} else {
8656e91bba0SGirish Moodalbail 		for (head = aobjmap.aobjmap_head; head != NULL;
8666e91bba0SGirish Moodalbail 		    head = head->am_next) {
8676e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
8686e91bba0SGirish Moodalbail 				return (EEXIST);
8696e91bba0SGirish Moodalbail 		}
8706e91bba0SGirish Moodalbail 		nodep->am_nextnum = nextnum;
8716e91bba0SGirish Moodalbail 	}
8726e91bba0SGirish Moodalbail 	return (i_ipmgmt_add_amnode(nodep));
8736e91bba0SGirish Moodalbail }
8746e91bba0SGirish Moodalbail 
8756e91bba0SGirish Moodalbail /*
8766e91bba0SGirish Moodalbail  * Performs following operations on the global `aobjmap' linked list.
8776e91bba0SGirish Moodalbail  * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
8786e91bba0SGirish Moodalbail  * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
8796e91bba0SGirish Moodalbail  * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
880ec3706caSVasumathi Sundaram  * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
8816e91bba0SGirish Moodalbail  */
8826e91bba0SGirish Moodalbail int
8836e91bba0SGirish Moodalbail ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
8846e91bba0SGirish Moodalbail {
885ec3706caSVasumathi Sundaram 	ipmgmt_aobjmap_t	*head, *prev, *matched = NULL;
8866e91bba0SGirish Moodalbail 	boolean_t		update = B_TRUE;
8876e91bba0SGirish Moodalbail 	int			err = 0;
8886e91bba0SGirish Moodalbail 	ipadm_db_op_t		db_op;
8896e91bba0SGirish Moodalbail 
8906e91bba0SGirish Moodalbail 	(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
8916e91bba0SGirish Moodalbail 
8926e91bba0SGirish Moodalbail 	head = aobjmap.aobjmap_head;
8936e91bba0SGirish Moodalbail 	switch (op) {
8946e91bba0SGirish Moodalbail 	case ADDROBJ_ADD:
8956e91bba0SGirish Moodalbail 		/*
8966e91bba0SGirish Moodalbail 		 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
8976e91bba0SGirish Moodalbail 		 * update, else add the new node.
8986e91bba0SGirish Moodalbail 		 */
8996e91bba0SGirish Moodalbail 		for (; head != NULL; head = head->am_next) {
900ec3706caSVasumathi Sundaram 			/*
901ec3706caSVasumathi Sundaram 			 * For IPv6, we need to distinguish between the
902ec3706caSVasumathi Sundaram 			 * linklocal and non-linklocal nodes
903ec3706caSVasumathi Sundaram 			 */
9046e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname,
905ec3706caSVasumathi Sundaram 			    nodep->am_aobjname) == 0 &&
906ec3706caSVasumathi Sundaram 			    (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
907ec3706caSVasumathi Sundaram 			    head->am_linklocal == nodep->am_linklocal))
9086e91bba0SGirish Moodalbail 				break;
9096e91bba0SGirish Moodalbail 		}
9106e91bba0SGirish Moodalbail 
9116e91bba0SGirish Moodalbail 		if (head != NULL) {
9126e91bba0SGirish Moodalbail 			/* update the node */
9136e91bba0SGirish Moodalbail 			(void) strlcpy(head->am_ifname, nodep->am_ifname,
9146e91bba0SGirish Moodalbail 			    sizeof (head->am_ifname));
9156e91bba0SGirish Moodalbail 			head->am_lnum = nodep->am_lnum;
9166e91bba0SGirish Moodalbail 			head->am_family = nodep->am_family;
9176e91bba0SGirish Moodalbail 			head->am_flags = nodep->am_flags;
9186e91bba0SGirish Moodalbail 			head->am_atype = nodep->am_atype;
9196e91bba0SGirish Moodalbail 			if (head->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
9206e91bba0SGirish Moodalbail 				head->am_ifid = nodep->am_ifid;
9216e91bba0SGirish Moodalbail 				head->am_linklocal = nodep->am_linklocal;
9226e91bba0SGirish Moodalbail 			}
9236e91bba0SGirish Moodalbail 		} else {
9246e91bba0SGirish Moodalbail 			for (head = aobjmap.aobjmap_head; head != NULL;
9256e91bba0SGirish Moodalbail 			    head = head->am_next) {
9266e91bba0SGirish Moodalbail 				if (strcmp(head->am_ifname,
9276e91bba0SGirish Moodalbail 				    nodep->am_ifname) == 0)
9286e91bba0SGirish Moodalbail 					break;
9296e91bba0SGirish Moodalbail 			}
9306e91bba0SGirish Moodalbail 			nodep->am_nextnum = (head == NULL ? 0 :
9316e91bba0SGirish Moodalbail 			    head->am_nextnum);
9326e91bba0SGirish Moodalbail 			err = i_ipmgmt_add_amnode(nodep);
9336e91bba0SGirish Moodalbail 		}
9346e91bba0SGirish Moodalbail 		db_op = IPADM_DB_WRITE;
9356e91bba0SGirish Moodalbail 		break;
9366e91bba0SGirish Moodalbail 	case ADDROBJ_DELETE:
9376e91bba0SGirish Moodalbail 		prev = head;
9386e91bba0SGirish Moodalbail 		while (head != NULL) {
9396e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname,
9406e91bba0SGirish Moodalbail 			    nodep->am_aobjname) == 0) {
9416e91bba0SGirish Moodalbail 				nodep->am_atype = head->am_atype;
9426e91bba0SGirish Moodalbail 				/*
9436e91bba0SGirish Moodalbail 				 * There could be multiple IPV6_ADDRCONF nodes,
9446e91bba0SGirish Moodalbail 				 * with same address object name, so check for
9456e91bba0SGirish Moodalbail 				 * logical number also.
9466e91bba0SGirish Moodalbail 				 */
9476e91bba0SGirish Moodalbail 				if (head->am_atype !=
9486e91bba0SGirish Moodalbail 				    IPADM_ADDR_IPV6_ADDRCONF ||
9496e91bba0SGirish Moodalbail 				    nodep->am_lnum == head->am_lnum)
9506e91bba0SGirish Moodalbail 					break;
9516e91bba0SGirish Moodalbail 			}
9526e91bba0SGirish Moodalbail 			prev = head;
9536e91bba0SGirish Moodalbail 			head = head->am_next;
9546e91bba0SGirish Moodalbail 		}
9556e91bba0SGirish Moodalbail 		if (head != NULL) {
9566e91bba0SGirish Moodalbail 			/*
9576e91bba0SGirish Moodalbail 			 * If the address object is in both active and
9586e91bba0SGirish Moodalbail 			 * persistent configuration and the user is deleting it
9596e91bba0SGirish Moodalbail 			 * only from active configuration then mark this node
9606e91bba0SGirish Moodalbail 			 * for deletion by reseting IPMGMT_ACTIVE bit.
9616e91bba0SGirish Moodalbail 			 * With this the same address object name cannot
9626e91bba0SGirish Moodalbail 			 * be reused until it is permanently removed.
9636e91bba0SGirish Moodalbail 			 */
9646e91bba0SGirish Moodalbail 			if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
9656e91bba0SGirish Moodalbail 			    nodep->am_flags == IPMGMT_ACTIVE) {
9666e91bba0SGirish Moodalbail 				/* Update flags in the in-memory map. */
9676e91bba0SGirish Moodalbail 				head->am_flags &= ~IPMGMT_ACTIVE;
9686e91bba0SGirish Moodalbail 				head->am_lnum = -1;
9696e91bba0SGirish Moodalbail 
9706e91bba0SGirish Moodalbail 				/* Update info in file. */
9716e91bba0SGirish Moodalbail 				db_op = IPADM_DB_WRITE;
9726e91bba0SGirish Moodalbail 				*nodep = *head;
9736e91bba0SGirish Moodalbail 			} else {
9746e91bba0SGirish Moodalbail 				(void) strlcpy(nodep->am_ifname,
9756e91bba0SGirish Moodalbail 				    head->am_ifname,
9766e91bba0SGirish Moodalbail 				    sizeof (nodep->am_ifname));
9776e91bba0SGirish Moodalbail 				/* otherwise delete the node */
9786e91bba0SGirish Moodalbail 				if (head == aobjmap.aobjmap_head)
9796e91bba0SGirish Moodalbail 					aobjmap.aobjmap_head = head->am_next;
9806e91bba0SGirish Moodalbail 				else
9816e91bba0SGirish Moodalbail 					prev->am_next = head->am_next;
9826e91bba0SGirish Moodalbail 				free(head);
9836e91bba0SGirish Moodalbail 				db_op = IPADM_DB_DELETE;
9846e91bba0SGirish Moodalbail 			}
9856e91bba0SGirish Moodalbail 		} else {
9866e91bba0SGirish Moodalbail 			err = ENOENT;
9876e91bba0SGirish Moodalbail 		}
9886e91bba0SGirish Moodalbail 		break;
9896e91bba0SGirish Moodalbail 	case ADDROBJ_LOOKUPADD:
9906e91bba0SGirish Moodalbail 		err = i_ipmgmt_lookupadd_amnode(nodep);
9916e91bba0SGirish Moodalbail 		update = B_FALSE;
9926e91bba0SGirish Moodalbail 		break;
993ec3706caSVasumathi Sundaram 	case ADDROBJ_SETLIFNUM:
994ec3706caSVasumathi Sundaram 		update = B_FALSE;
995ec3706caSVasumathi Sundaram 		for (; head != NULL; head = head->am_next) {
996ec3706caSVasumathi Sundaram 			if (strcmp(head->am_ifname,
997ec3706caSVasumathi Sundaram 			    nodep->am_ifname) == 0 &&
998ec3706caSVasumathi Sundaram 			    head->am_family == nodep->am_family &&
999ec3706caSVasumathi Sundaram 			    head->am_lnum == nodep->am_lnum) {
1000ec3706caSVasumathi Sundaram 				err = EEXIST;
1001ec3706caSVasumathi Sundaram 				break;
1002ec3706caSVasumathi Sundaram 			}
1003ec3706caSVasumathi Sundaram 			if (strcmp(head->am_aobjname,
1004ec3706caSVasumathi Sundaram 			    nodep->am_aobjname) == 0) {
1005ec3706caSVasumathi Sundaram 				matched = head;
1006ec3706caSVasumathi Sundaram 			}
1007ec3706caSVasumathi Sundaram 		}
1008ec3706caSVasumathi Sundaram 		if (err == EEXIST)
1009ec3706caSVasumathi Sundaram 			break;
1010ec3706caSVasumathi Sundaram 		if (matched != NULL) {
1011ec3706caSVasumathi Sundaram 			/* update the lifnum */
1012ec3706caSVasumathi Sundaram 			matched->am_lnum = nodep->am_lnum;
1013ec3706caSVasumathi Sundaram 		} else {
1014ec3706caSVasumathi Sundaram 			err = ENOENT;
1015ec3706caSVasumathi Sundaram 		}
1016ec3706caSVasumathi Sundaram 		break;
10176e91bba0SGirish Moodalbail 	default:
10186e91bba0SGirish Moodalbail 		assert(0);
10196e91bba0SGirish Moodalbail 	}
10206e91bba0SGirish Moodalbail 
10216e91bba0SGirish Moodalbail 	if (err == 0 && update)
10226e91bba0SGirish Moodalbail 		err = ipmgmt_persist_aobjmap(nodep, db_op);
10236e91bba0SGirish Moodalbail 
10246e91bba0SGirish Moodalbail 	(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
10256e91bba0SGirish Moodalbail 
10266e91bba0SGirish Moodalbail 	return (err);
10276e91bba0SGirish Moodalbail }
10286e91bba0SGirish Moodalbail 
10296e91bba0SGirish Moodalbail /*
10306e91bba0SGirish Moodalbail  * Given a node in `aobjmap', this function converts it into nvlist_t structure.
10316e91bba0SGirish Moodalbail  * The content to be written to DB must be represented as nvlist_t.
10326e91bba0SGirish Moodalbail  */
10336e91bba0SGirish Moodalbail static int
10346e91bba0SGirish Moodalbail i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
10356e91bba0SGirish Moodalbail {
10366e91bba0SGirish Moodalbail 	int	err;
10376e91bba0SGirish Moodalbail 	char	strval[IPMGMT_STRSIZE];
10386e91bba0SGirish Moodalbail 
10396e91bba0SGirish Moodalbail 	*nvl = NULL;
10406e91bba0SGirish Moodalbail 	if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
10416e91bba0SGirish Moodalbail 		goto fail;
10426e91bba0SGirish Moodalbail 
10436e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
10446e91bba0SGirish Moodalbail 	    np->am_aobjname)) != 0)
10456e91bba0SGirish Moodalbail 		goto fail;
10466e91bba0SGirish Moodalbail 
10476e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
10486e91bba0SGirish Moodalbail 	    np->am_ifname)) != 0)
10496e91bba0SGirish Moodalbail 		goto fail;
10506e91bba0SGirish Moodalbail 
10516e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
10526e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
10536e91bba0SGirish Moodalbail 		goto fail;
10546e91bba0SGirish Moodalbail 
10556e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
10566e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
10576e91bba0SGirish Moodalbail 		goto fail;
10586e91bba0SGirish Moodalbail 
10596e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
10606e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
10616e91bba0SGirish Moodalbail 		goto fail;
10626e91bba0SGirish Moodalbail 
10636e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
10646e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
10656e91bba0SGirish Moodalbail 		goto fail;
10666e91bba0SGirish Moodalbail 
10676e91bba0SGirish Moodalbail 	if (np->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
10686e91bba0SGirish Moodalbail 		struct sockaddr_in6	*in6;
10696e91bba0SGirish Moodalbail 
10706e91bba0SGirish Moodalbail 		in6 = (struct sockaddr_in6 *)&np->am_ifid;
10716e91bba0SGirish Moodalbail 		if (np->am_linklocal &&
10726e91bba0SGirish Moodalbail 		    IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
10736e91bba0SGirish Moodalbail 			if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
10746e91bba0SGirish Moodalbail 			    "default")) != 0)
10756e91bba0SGirish Moodalbail 				goto fail;
10766e91bba0SGirish Moodalbail 		} else {
10776e91bba0SGirish Moodalbail 			if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
10786e91bba0SGirish Moodalbail 			    IPMGMT_STRSIZE) == NULL) {
10796e91bba0SGirish Moodalbail 				err = errno;
10806e91bba0SGirish Moodalbail 				goto fail;
10816e91bba0SGirish Moodalbail 			}
10826e91bba0SGirish Moodalbail 			if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
10836e91bba0SGirish Moodalbail 			    strval)) != 0)
10846e91bba0SGirish Moodalbail 				goto fail;
10856e91bba0SGirish Moodalbail 		}
10866e91bba0SGirish Moodalbail 	} else {
10876e91bba0SGirish Moodalbail 		if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
10886e91bba0SGirish Moodalbail 		    "")) != 0)
10896e91bba0SGirish Moodalbail 			goto fail;
10906e91bba0SGirish Moodalbail 	}
10916e91bba0SGirish Moodalbail 	return (err);
10926e91bba0SGirish Moodalbail fail:
10936e91bba0SGirish Moodalbail 	nvlist_free(*nvl);
10946e91bba0SGirish Moodalbail 	return (err);
10956e91bba0SGirish Moodalbail }
10966e91bba0SGirish Moodalbail 
10976e91bba0SGirish Moodalbail /*
10986e91bba0SGirish Moodalbail  * Read the aobjmap data store and build the in-memory representation
10996e91bba0SGirish Moodalbail  * of the aobjmap. We don't need to hold any locks while building this as
11006e91bba0SGirish Moodalbail  * we do this in very early stage of daemon coming up, even before the door
11016e91bba0SGirish Moodalbail  * is opened.
11026e91bba0SGirish Moodalbail  */
11036e91bba0SGirish Moodalbail /* ARGSUSED */
11046e91bba0SGirish Moodalbail extern boolean_t
11056e91bba0SGirish Moodalbail ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
11066e91bba0SGirish Moodalbail     int *errp)
11076e91bba0SGirish Moodalbail {
11086e91bba0SGirish Moodalbail 	nvpair_t		*nvp = NULL;
11096e91bba0SGirish Moodalbail 	char			*name, *strval = NULL;
11106e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t 	node;
11116e91bba0SGirish Moodalbail 	struct sockaddr_in6	*in6;
11126e91bba0SGirish Moodalbail 
11136e91bba0SGirish Moodalbail 	*errp = 0;
11146e91bba0SGirish Moodalbail 	node.am_next = NULL;
11156e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
11166e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
11176e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
11186e91bba0SGirish Moodalbail 
11196e91bba0SGirish Moodalbail 		if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
11206e91bba0SGirish Moodalbail 			return (B_TRUE);
11216e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
11226e91bba0SGirish Moodalbail 			(void) strlcpy(node.am_aobjname, strval,
11236e91bba0SGirish Moodalbail 			    sizeof (node.am_aobjname));
11246e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
11256e91bba0SGirish Moodalbail 			(void) strlcpy(node.am_ifname, strval,
11266e91bba0SGirish Moodalbail 			    sizeof (node.am_ifname));
11276e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
11286e91bba0SGirish Moodalbail 			node.am_lnum = atoi(strval);
11296e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
11306e91bba0SGirish Moodalbail 			node.am_family = (sa_family_t)atoi(strval);
11316e91bba0SGirish Moodalbail 		} else if (strcmp(FLAGS, name) == 0) {
11326e91bba0SGirish Moodalbail 			node.am_flags = atoi(strval);
11336e91bba0SGirish Moodalbail 		} else if (strcmp(ATYPE, name) == 0) {
11346e91bba0SGirish Moodalbail 			node.am_atype = (ipadm_addr_type_t)atoi(strval);
11356e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
11366e91bba0SGirish Moodalbail 			if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
11376e91bba0SGirish Moodalbail 				in6 = (struct sockaddr_in6 *)&node.am_ifid;
11386e91bba0SGirish Moodalbail 				if (strcmp(strval, "default") == 0) {
11396e91bba0SGirish Moodalbail 					bzero(in6, sizeof (node.am_ifid));
11406e91bba0SGirish Moodalbail 					node.am_linklocal = B_TRUE;
11416e91bba0SGirish Moodalbail 				} else {
11426e91bba0SGirish Moodalbail 					(void) inet_pton(AF_INET6, strval,
11436e91bba0SGirish Moodalbail 					    &in6->sin6_addr);
11446e91bba0SGirish Moodalbail 					if (IN6_IS_ADDR_UNSPECIFIED(
11456e91bba0SGirish Moodalbail 					    &in6->sin6_addr))
11466e91bba0SGirish Moodalbail 						node.am_linklocal = B_TRUE;
11476e91bba0SGirish Moodalbail 				}
11486e91bba0SGirish Moodalbail 			}
11496e91bba0SGirish Moodalbail 		}
11506e91bba0SGirish Moodalbail 	}
11516e91bba0SGirish Moodalbail 
11526e91bba0SGirish Moodalbail 	/* we have all the information we need, add the node */
11536e91bba0SGirish Moodalbail 	*errp = i_ipmgmt_add_amnode(&node);
11546e91bba0SGirish Moodalbail 
11556e91bba0SGirish Moodalbail 	return (B_TRUE);
11566e91bba0SGirish Moodalbail }
11576e91bba0SGirish Moodalbail 
11586e91bba0SGirish Moodalbail /*
11596e91bba0SGirish Moodalbail  * Updates an entry from the temporary cache file, which matches the given
11606e91bba0SGirish Moodalbail  * address object name.
11616e91bba0SGirish Moodalbail  */
11626e91bba0SGirish Moodalbail /* ARGSUSED */
11636e91bba0SGirish Moodalbail static boolean_t
11646e91bba0SGirish Moodalbail ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
11656e91bba0SGirish Moodalbail     size_t buflen, int *errp)
11666e91bba0SGirish Moodalbail {
11676e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	*cb = arg;
11686e91bba0SGirish Moodalbail 	nvlist_t		*in_nvl = cb->dbw_nvl;
11696e91bba0SGirish Moodalbail 	uint32_t		flags = cb->dbw_flags;
11706e91bba0SGirish Moodalbail 	char			*db_lifnumstr = NULL, *in_lifnumstr = NULL;
11716e91bba0SGirish Moodalbail 
11726e91bba0SGirish Moodalbail 	*errp = 0;
11736e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
11746e91bba0SGirish Moodalbail 		return (B_TRUE);
11756e91bba0SGirish Moodalbail 
11766e91bba0SGirish Moodalbail 	if (flags & IPMGMT_ATYPE_V6ACONF) {
11776e91bba0SGirish Moodalbail 		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
11786e91bba0SGirish Moodalbail 		    &db_lifnumstr) != 0 ||
11796e91bba0SGirish Moodalbail 		    nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
11806e91bba0SGirish Moodalbail 		    &in_lifnumstr) != 0 ||
11816e91bba0SGirish Moodalbail 		    (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
11826e91bba0SGirish Moodalbail 		    strcmp(db_lifnumstr, in_lifnumstr) != 0))
11836e91bba0SGirish Moodalbail 			return (B_TRUE);
11846e91bba0SGirish Moodalbail 	}
11856e91bba0SGirish Moodalbail 
11866e91bba0SGirish Moodalbail 	/* we found the match */
11876e91bba0SGirish Moodalbail 	(void) memset(buf, 0, buflen);
11886e91bba0SGirish Moodalbail 	if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
11896e91bba0SGirish Moodalbail 		/* buffer overflow */
11906e91bba0SGirish Moodalbail 		*errp = ENOBUFS;
11916e91bba0SGirish Moodalbail 	}
11926e91bba0SGirish Moodalbail 
11936e91bba0SGirish Moodalbail 	/* stop the walker */
11946e91bba0SGirish Moodalbail 	return (B_FALSE);
11956e91bba0SGirish Moodalbail }
11966e91bba0SGirish Moodalbail 
11976e91bba0SGirish Moodalbail /*
11986e91bba0SGirish Moodalbail  * Deletes an entry from the temporary cache file, which matches the given
11996e91bba0SGirish Moodalbail  * address object name.
12006e91bba0SGirish Moodalbail  */
12016e91bba0SGirish Moodalbail /* ARGSUSED */
12026e91bba0SGirish Moodalbail static boolean_t
12036e91bba0SGirish Moodalbail ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
12046e91bba0SGirish Moodalbail     size_t buflen, int *errp)
12056e91bba0SGirish Moodalbail {
12066e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*nodep = arg;
12076e91bba0SGirish Moodalbail 	char			*db_lifnumstr = NULL;
12086e91bba0SGirish Moodalbail 
12096e91bba0SGirish Moodalbail 	*errp = 0;
12106e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
12116e91bba0SGirish Moodalbail 	    nodep->am_aobjname))
12126e91bba0SGirish Moodalbail 		return (B_TRUE);
12136e91bba0SGirish Moodalbail 
12146e91bba0SGirish Moodalbail 	if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
12156e91bba0SGirish Moodalbail 		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
12166e91bba0SGirish Moodalbail 		    &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
12176e91bba0SGirish Moodalbail 			return (B_TRUE);
12186e91bba0SGirish Moodalbail 	}
12196e91bba0SGirish Moodalbail 
12206e91bba0SGirish Moodalbail 	/* we found the match, delete the line from the db */
12216e91bba0SGirish Moodalbail 	buf[0] = '\0';
12226e91bba0SGirish Moodalbail 
12236e91bba0SGirish Moodalbail 	/* stop the walker */
12246e91bba0SGirish Moodalbail 	return (B_FALSE);
12256e91bba0SGirish Moodalbail }
12266e91bba0SGirish Moodalbail 
12276e91bba0SGirish Moodalbail /*
12286e91bba0SGirish Moodalbail  * Adds or deletes aobjmap node information into a temporary cache file.
12296e91bba0SGirish Moodalbail  */
12306e91bba0SGirish Moodalbail extern int
12316e91bba0SGirish Moodalbail ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
12326e91bba0SGirish Moodalbail {
12336e91bba0SGirish Moodalbail 	int			err;
12346e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	cb;
12356e91bba0SGirish Moodalbail 	nvlist_t		*nvl = NULL;
12366e91bba0SGirish Moodalbail 
12376e91bba0SGirish Moodalbail 	if (op == IPADM_DB_WRITE) {
12386e91bba0SGirish Moodalbail 		if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
12396e91bba0SGirish Moodalbail 			return (err);
12406e91bba0SGirish Moodalbail 		cb.dbw_nvl = nvl;
12416e91bba0SGirish Moodalbail 		if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
12426e91bba0SGirish Moodalbail 			cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
12436e91bba0SGirish Moodalbail 		else
12446e91bba0SGirish Moodalbail 			cb.dbw_flags = 0;
12456e91bba0SGirish Moodalbail 
12466e91bba0SGirish Moodalbail 		err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
12476e91bba0SGirish Moodalbail 		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
12486e91bba0SGirish Moodalbail 		nvlist_free(nvl);
12496e91bba0SGirish Moodalbail 	} else {
12506e91bba0SGirish Moodalbail 		assert(op == IPADM_DB_DELETE);
12516e91bba0SGirish Moodalbail 
12526e91bba0SGirish Moodalbail 		err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
12536e91bba0SGirish Moodalbail 		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
12546e91bba0SGirish Moodalbail 	}
12556e91bba0SGirish Moodalbail 	return (err);
12566e91bba0SGirish Moodalbail }
1257550b6e40SSowmini Varadhan 
1258*8887b57dSGirish Moodalbail /*
1259*8887b57dSGirish Moodalbail  * upgrades the ipadm data-store. It renames all the old private protocol
1260*8887b57dSGirish Moodalbail  * property names which start with leading protocol names to begin with
1261*8887b57dSGirish Moodalbail  * IPADM_PRIV_PROP_PREFIX.
1262*8887b57dSGirish Moodalbail  */
1263*8887b57dSGirish Moodalbail /* ARGSUSED */
1264*8887b57dSGirish Moodalbail boolean_t
1265*8887b57dSGirish Moodalbail ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
1266*8887b57dSGirish Moodalbail     int *errp)
1267*8887b57dSGirish Moodalbail {
1268*8887b57dSGirish Moodalbail 	nvpair_t	*nvp;
1269*8887b57dSGirish Moodalbail 	char		*name, *pname = NULL, *protostr = NULL, *pval = NULL;
1270*8887b57dSGirish Moodalbail 	uint_t		proto, nproto;
1271*8887b57dSGirish Moodalbail 	char		nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
1272*8887b57dSGirish Moodalbail 
1273*8887b57dSGirish Moodalbail 	*errp = 0;
1274*8887b57dSGirish Moodalbail 	/*
1275*8887b57dSGirish Moodalbail 	 * We are interested in lines which contain protocol properties. We
1276*8887b57dSGirish Moodalbail 	 * walk through other lines in the DB.
1277*8887b57dSGirish Moodalbail 	 */
1278*8887b57dSGirish Moodalbail 	if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
1279*8887b57dSGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
1280*8887b57dSGirish Moodalbail 		return (B_TRUE);
1281*8887b57dSGirish Moodalbail 	}
1282*8887b57dSGirish Moodalbail 	assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
1283550b6e40SSowmini Varadhan 
1284550b6e40SSowmini Varadhan 	/*
1285*8887b57dSGirish Moodalbail 	 * extract the propname from the `db_nvl' and also extract the
1286*8887b57dSGirish Moodalbail 	 * protocol from the `db_nvl'.
1287550b6e40SSowmini Varadhan 	 */
1288*8887b57dSGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1289*8887b57dSGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1290*8887b57dSGirish Moodalbail 		name = nvpair_name(nvp);
1291*8887b57dSGirish Moodalbail 		if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
1292*8887b57dSGirish Moodalbail 			if (nvpair_value_string(nvp, &protostr) != 0)
1293*8887b57dSGirish Moodalbail 				return (B_TRUE);
1294*8887b57dSGirish Moodalbail 		} else {
1295*8887b57dSGirish Moodalbail 			assert(!IPADM_PRIV_NVP(name));
1296*8887b57dSGirish Moodalbail 			pname = name;
1297*8887b57dSGirish Moodalbail 			if (nvpair_value_string(nvp, &pval) != 0)
1298*8887b57dSGirish Moodalbail 				return (B_TRUE);
1299*8887b57dSGirish Moodalbail 		}
1300*8887b57dSGirish Moodalbail 	}
1301*8887b57dSGirish Moodalbail 
1302*8887b57dSGirish Moodalbail 	/* if the private property is in the right format return */
1303*8887b57dSGirish Moodalbail 	if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
1304*8887b57dSGirish Moodalbail 	    strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1305*8887b57dSGirish Moodalbail 		return (B_TRUE);
1306*8887b57dSGirish Moodalbail 	}
1307*8887b57dSGirish Moodalbail 	/* if it's a public property move onto the next property */
1308*8887b57dSGirish Moodalbail 	nproto = proto = ipadm_str2proto(protostr);
1309*8887b57dSGirish Moodalbail 	if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
1310*8887b57dSGirish Moodalbail 	    &nproto) != 0) {
1311*8887b57dSGirish Moodalbail 		return (B_TRUE);
1312*8887b57dSGirish Moodalbail 	}
1313*8887b57dSGirish Moodalbail 
1314*8887b57dSGirish Moodalbail 	/* replace the old protocol with new protocol, if required */
1315*8887b57dSGirish Moodalbail 	if (nproto != proto) {
1316*8887b57dSGirish Moodalbail 		protostr = ipadm_proto2str(nproto);
1317*8887b57dSGirish Moodalbail 		if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
1318*8887b57dSGirish Moodalbail 		    protostr) != 0) {
1319*8887b57dSGirish Moodalbail 			return (B_TRUE);
1320*8887b57dSGirish Moodalbail 		}
1321*8887b57dSGirish Moodalbail 	}
1322*8887b57dSGirish Moodalbail 
1323*8887b57dSGirish Moodalbail 	/* replace the old property name with new property name, if required */
1324*8887b57dSGirish Moodalbail 	/* add the prefix to property name */
1325*8887b57dSGirish Moodalbail 	(void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
1326*8887b57dSGirish Moodalbail 	if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
1327*8887b57dSGirish Moodalbail 	    nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
1328*8887b57dSGirish Moodalbail 		return (B_TRUE);
1329*8887b57dSGirish Moodalbail 	}
1330*8887b57dSGirish Moodalbail 	(void) memset(buf, 0, buflen);
1331*8887b57dSGirish Moodalbail 	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1332*8887b57dSGirish Moodalbail 		/* buffer overflow */
1333*8887b57dSGirish Moodalbail 		*errp = ENOBUFS;
1334*8887b57dSGirish Moodalbail 	}
1335*8887b57dSGirish Moodalbail 	return (B_TRUE);
1336*8887b57dSGirish Moodalbail }
1337*8887b57dSGirish Moodalbail 
1338*8887b57dSGirish Moodalbail /*
1339*8887b57dSGirish Moodalbail  * Called during boot.
1340*8887b57dSGirish Moodalbail  *
1341*8887b57dSGirish Moodalbail  * Walk through the DB and apply all the global module properties. We plow
1342*8887b57dSGirish Moodalbail  * through the DB even if we fail to apply property.
1343*8887b57dSGirish Moodalbail  */
1344*8887b57dSGirish Moodalbail /* ARGSUSED */
1345*8887b57dSGirish Moodalbail static boolean_t
1346*8887b57dSGirish Moodalbail ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1347*8887b57dSGirish Moodalbail     int *errp)
1348*8887b57dSGirish Moodalbail {
1349*8887b57dSGirish Moodalbail 	ipadm_handle_t	iph = cbarg;
1350*8887b57dSGirish Moodalbail 	nvpair_t	*nvp, *pnvp;
1351*8887b57dSGirish Moodalbail 	char		*strval = NULL, *name, *mod = NULL, *pname;
1352*8887b57dSGirish Moodalbail 	char		tmpstr[IPMGMT_STRSIZE];
1353*8887b57dSGirish Moodalbail 	uint_t		proto;
1354*8887b57dSGirish Moodalbail 
1355*8887b57dSGirish Moodalbail 	/*
1356*8887b57dSGirish Moodalbail 	 * We could have used nvl_exists() directly, however we need several
1357*8887b57dSGirish Moodalbail 	 * calls to it and each call traverses the list. Since this codepath
1358*8887b57dSGirish Moodalbail 	 * is exercised during boot, let's traverse the list ourselves and do
1359*8887b57dSGirish Moodalbail 	 * the necessary checks.
1360*8887b57dSGirish Moodalbail 	 */
1361*8887b57dSGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1362*8887b57dSGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1363*8887b57dSGirish Moodalbail 		name = nvpair_name(nvp);
1364*8887b57dSGirish Moodalbail 		if (IPADM_PRIV_NVP(name)) {
1365*8887b57dSGirish Moodalbail 			if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1366*8887b57dSGirish Moodalbail 			    strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1367*8887b57dSGirish Moodalbail 				return (B_TRUE);
1368*8887b57dSGirish Moodalbail 			else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1369*8887b57dSGirish Moodalbail 			    nvpair_value_string(nvp, &mod) != 0)
1370*8887b57dSGirish Moodalbail 				return (B_TRUE);
1371*8887b57dSGirish Moodalbail 		} else {
1372*8887b57dSGirish Moodalbail 			/* possible a property */
1373*8887b57dSGirish Moodalbail 			pnvp = nvp;
1374*8887b57dSGirish Moodalbail 		}
1375*8887b57dSGirish Moodalbail 	}
1376*8887b57dSGirish Moodalbail 
1377*8887b57dSGirish Moodalbail 	/* if we are here than we found a global property */
1378*8887b57dSGirish Moodalbail 	assert(mod != NULL);
1379*8887b57dSGirish Moodalbail 	assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1380*8887b57dSGirish Moodalbail 
1381*8887b57dSGirish Moodalbail 	proto = ipadm_str2proto(mod);
1382*8887b57dSGirish Moodalbail 	name = nvpair_name(pnvp);
1383*8887b57dSGirish Moodalbail 	if (nvpair_value_string(pnvp, &strval) == 0) {
1384*8887b57dSGirish Moodalbail 		if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1385*8887b57dSGirish Moodalbail 		    strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1386*8887b57dSGirish Moodalbail 			/* private protocol property */
1387*8887b57dSGirish Moodalbail 			pname = &name[1];
1388*8887b57dSGirish Moodalbail 		} else if (ipadm_legacy2new_propname(name, tmpstr,
1389*8887b57dSGirish Moodalbail 		    sizeof (tmpstr), &proto) == 0) {
1390*8887b57dSGirish Moodalbail 			pname = tmpstr;
1391*8887b57dSGirish Moodalbail 		} else {
1392*8887b57dSGirish Moodalbail 			pname = name;
1393*8887b57dSGirish Moodalbail 		}
1394*8887b57dSGirish Moodalbail 		if (ipadm_set_prop(iph, pname, strval, proto,
1395*8887b57dSGirish Moodalbail 		    IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1396*8887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1397*8887b57dSGirish Moodalbail 			    pname);
1398*8887b57dSGirish Moodalbail 		}
1399*8887b57dSGirish Moodalbail 	}
1400*8887b57dSGirish Moodalbail 
1401*8887b57dSGirish Moodalbail 	return (B_TRUE);
1402*8887b57dSGirish Moodalbail }
1403*8887b57dSGirish Moodalbail 
1404*8887b57dSGirish Moodalbail /* initialize global module properties */
1405*8887b57dSGirish Moodalbail void
1406*8887b57dSGirish Moodalbail ipmgmt_init_prop()
1407*8887b57dSGirish Moodalbail {
1408*8887b57dSGirish Moodalbail 	ipadm_handle_t	iph = NULL;
1409*8887b57dSGirish Moodalbail 
1410*8887b57dSGirish Moodalbail 	if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
1411*8887b57dSGirish Moodalbail 		ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
1412*8887b57dSGirish Moodalbail 		    "persisted protocol properties");
1413*8887b57dSGirish Moodalbail 		return;
1414*8887b57dSGirish Moodalbail 	}
1415*8887b57dSGirish Moodalbail 	/* ipmgmt_db_init() logs warnings if there are any issues */
1416*8887b57dSGirish Moodalbail 	(void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
1417*8887b57dSGirish Moodalbail 	ipadm_close(iph);
1418*8887b57dSGirish Moodalbail }
1419*8887b57dSGirish Moodalbail 
1420*8887b57dSGirish Moodalbail void
1421550b6e40SSowmini Varadhan ipmgmt_release_scf_resources(scf_resources_t *res)
1422550b6e40SSowmini Varadhan {
1423550b6e40SSowmini Varadhan 	scf_entry_destroy(res->sr_ent);
1424550b6e40SSowmini Varadhan 	scf_transaction_destroy(res->sr_tx);
1425550b6e40SSowmini Varadhan 	scf_value_destroy(res->sr_val);
1426550b6e40SSowmini Varadhan 	scf_property_destroy(res->sr_prop);
1427550b6e40SSowmini Varadhan 	scf_pg_destroy(res->sr_pg);
1428550b6e40SSowmini Varadhan 	scf_instance_destroy(res->sr_inst);
1429550b6e40SSowmini Varadhan 	(void) scf_handle_unbind(res->sr_handle);
1430550b6e40SSowmini Varadhan 	scf_handle_destroy(res->sr_handle);
1431550b6e40SSowmini Varadhan }
1432550b6e40SSowmini Varadhan 
1433550b6e40SSowmini Varadhan /*
1434*8887b57dSGirish Moodalbail  * It creates the necessary SCF handles and binds the given `fmri' to an
1435*8887b57dSGirish Moodalbail  * instance. These resources are required for retrieving property value,
1436*8887b57dSGirish Moodalbail  * creating property groups and modifying property values.
1437550b6e40SSowmini Varadhan  */
1438*8887b57dSGirish Moodalbail int
1439550b6e40SSowmini Varadhan ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1440550b6e40SSowmini Varadhan {
1441550b6e40SSowmini Varadhan 	res->sr_tx = NULL;
1442550b6e40SSowmini Varadhan 	res->sr_ent = NULL;
1443550b6e40SSowmini Varadhan 	res->sr_inst = NULL;
1444550b6e40SSowmini Varadhan 	res->sr_pg = NULL;
1445550b6e40SSowmini Varadhan 	res->sr_prop = NULL;
1446550b6e40SSowmini Varadhan 	res->sr_val = NULL;
1447550b6e40SSowmini Varadhan 
1448*8887b57dSGirish Moodalbail 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1449550b6e40SSowmini Varadhan 		return (-1);
1450550b6e40SSowmini Varadhan 
1451550b6e40SSowmini Varadhan 	if (scf_handle_bind(res->sr_handle) != 0) {
1452550b6e40SSowmini Varadhan 		scf_handle_destroy(res->sr_handle);
1453550b6e40SSowmini Varadhan 		return (-1);
1454550b6e40SSowmini Varadhan 	}
1455*8887b57dSGirish Moodalbail 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1456550b6e40SSowmini Varadhan 		goto failure;
1457550b6e40SSowmini Varadhan 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1458550b6e40SSowmini Varadhan 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1459550b6e40SSowmini Varadhan 		goto failure;
1460550b6e40SSowmini Varadhan 	}
1461*8887b57dSGirish Moodalbail 	/* we will create the rest of the resources on demand */
1462550b6e40SSowmini Varadhan 	return (0);
1463550b6e40SSowmini Varadhan 
1464550b6e40SSowmini Varadhan failure:
1465*8887b57dSGirish Moodalbail 	ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
1466*8887b57dSGirish Moodalbail 	    scf_strerror(scf_error()));
1467550b6e40SSowmini Varadhan 	ipmgmt_release_scf_resources(res);
1468550b6e40SSowmini Varadhan 	return (-1);
1469550b6e40SSowmini Varadhan }
1470550b6e40SSowmini Varadhan 
1471*8887b57dSGirish Moodalbail /*
1472*8887b57dSGirish Moodalbail  * persists the `pval' for a given property `pname' in SCF. The only supported
1473*8887b57dSGirish Moodalbail  * SCF property types are INTEGER and ASTRING.
1474*8887b57dSGirish Moodalbail  */
1475550b6e40SSowmini Varadhan static int
1476*8887b57dSGirish Moodalbail ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
1477*8887b57dSGirish Moodalbail     scf_type_t ptype)
1478550b6e40SSowmini Varadhan {
1479550b6e40SSowmini Varadhan 	int result = -1;
1480550b6e40SSowmini Varadhan 	boolean_t new;
1481550b6e40SSowmini Varadhan 
1482*8887b57dSGirish Moodalbail 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
1483*8887b57dSGirish Moodalbail 		goto failure;
1484*8887b57dSGirish Moodalbail 	switch (ptype) {
1485*8887b57dSGirish Moodalbail 	case SCF_TYPE_INTEGER:
1486*8887b57dSGirish Moodalbail 		scf_value_set_integer(res->sr_val, *(int64_t *)pval);
1487*8887b57dSGirish Moodalbail 		break;
1488*8887b57dSGirish Moodalbail 	case SCF_TYPE_ASTRING:
1489*8887b57dSGirish Moodalbail 		if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
1490*8887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Error setting string value %s "
1491*8887b57dSGirish Moodalbail 			    "for property %s: %s", pval, pname,
1492*8887b57dSGirish Moodalbail 			    scf_strerror(scf_error()));
1493550b6e40SSowmini Varadhan 			goto failure;
1494550b6e40SSowmini Varadhan 		}
1495*8887b57dSGirish Moodalbail 		break;
1496*8887b57dSGirish Moodalbail 	default:
1497*8887b57dSGirish Moodalbail 		goto failure;
1498*8887b57dSGirish Moodalbail 	}
1499*8887b57dSGirish Moodalbail 
1500*8887b57dSGirish Moodalbail 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
1501*8887b57dSGirish Moodalbail 		goto failure;
1502*8887b57dSGirish Moodalbail 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
1503*8887b57dSGirish Moodalbail 		goto failure;
1504*8887b57dSGirish Moodalbail 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
1505*8887b57dSGirish Moodalbail 		goto failure;
1506*8887b57dSGirish Moodalbail 
1507*8887b57dSGirish Moodalbail retry:
1508*8887b57dSGirish Moodalbail 	new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
1509*8887b57dSGirish Moodalbail 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
1510*8887b57dSGirish Moodalbail 		goto failure;
1511550b6e40SSowmini Varadhan 	if (new) {
1512550b6e40SSowmini Varadhan 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
1513*8887b57dSGirish Moodalbail 		    pname, ptype) == -1) {
1514550b6e40SSowmini Varadhan 			goto failure;
1515550b6e40SSowmini Varadhan 		}
1516550b6e40SSowmini Varadhan 	} else {
1517550b6e40SSowmini Varadhan 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
1518*8887b57dSGirish Moodalbail 		    pname, ptype) == -1) {
1519550b6e40SSowmini Varadhan 			goto failure;
1520550b6e40SSowmini Varadhan 		}
1521550b6e40SSowmini Varadhan 	}
1522550b6e40SSowmini Varadhan 
1523*8887b57dSGirish Moodalbail 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1524550b6e40SSowmini Varadhan 		goto failure;
1525550b6e40SSowmini Varadhan 
1526550b6e40SSowmini Varadhan 	result = scf_transaction_commit(res->sr_tx);
1527550b6e40SSowmini Varadhan 	if (result == 0) {
1528550b6e40SSowmini Varadhan 		scf_transaction_reset(res->sr_tx);
1529550b6e40SSowmini Varadhan 		if (scf_pg_update(res->sr_pg) == -1) {
1530550b6e40SSowmini Varadhan 			goto failure;
1531550b6e40SSowmini Varadhan 		}
1532550b6e40SSowmini Varadhan 		goto retry;
1533550b6e40SSowmini Varadhan 	}
1534550b6e40SSowmini Varadhan 	if (result == -1)
1535550b6e40SSowmini Varadhan 		goto failure;
1536550b6e40SSowmini Varadhan 	return (0);
1537550b6e40SSowmini Varadhan 
1538550b6e40SSowmini Varadhan failure:
1539*8887b57dSGirish Moodalbail 	ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
1540*8887b57dSGirish Moodalbail 	    scf_strerror(scf_error()));
1541550b6e40SSowmini Varadhan 	return (-1);
1542550b6e40SSowmini Varadhan }
1543550b6e40SSowmini Varadhan 
1544550b6e40SSowmini Varadhan /*
1545*8887b57dSGirish Moodalbail  * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
1546*8887b57dSGirish Moodalbail  * places it in `pval'.
1547550b6e40SSowmini Varadhan  */
1548*8887b57dSGirish Moodalbail static int
1549*8887b57dSGirish Moodalbail ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1550*8887b57dSGirish Moodalbail     void *pval, scf_type_t ptype)
1551550b6e40SSowmini Varadhan {
1552550b6e40SSowmini Varadhan 	ssize_t		numvals;
1553*8887b57dSGirish Moodalbail 	scf_simple_prop_t *prop;
1554*8887b57dSGirish Moodalbail 
1555*8887b57dSGirish Moodalbail 	prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1556*8887b57dSGirish Moodalbail 	numvals = scf_simple_prop_numvalues(prop);
1557*8887b57dSGirish Moodalbail 	if (numvals <= 0)
1558*8887b57dSGirish Moodalbail 		goto ret;
1559*8887b57dSGirish Moodalbail 	switch (ptype) {
1560*8887b57dSGirish Moodalbail 	case SCF_TYPE_INTEGER:
1561*8887b57dSGirish Moodalbail 		*(int64_t **)pval = scf_simple_prop_next_integer(prop);
1562*8887b57dSGirish Moodalbail 		break;
1563*8887b57dSGirish Moodalbail 	case SCF_TYPE_ASTRING:
1564*8887b57dSGirish Moodalbail 		*(char **)pval = scf_simple_prop_next_astring(prop);
1565*8887b57dSGirish Moodalbail 		break;
1566*8887b57dSGirish Moodalbail 	}
1567*8887b57dSGirish Moodalbail ret:
1568*8887b57dSGirish Moodalbail 	scf_simple_prop_free(prop);
1569*8887b57dSGirish Moodalbail 	return (numvals);
1570*8887b57dSGirish Moodalbail }
1571*8887b57dSGirish Moodalbail 
1572*8887b57dSGirish Moodalbail /*
1573*8887b57dSGirish Moodalbail  * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1574*8887b57dSGirish Moodalbail  */
1575*8887b57dSGirish Moodalbail static int
1576*8887b57dSGirish Moodalbail ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1577*8887b57dSGirish Moodalbail     void *pval, scf_type_t ptype)
1578*8887b57dSGirish Moodalbail {
1579550b6e40SSowmini Varadhan 	scf_error_t		err;
1580550b6e40SSowmini Varadhan 
1581*8887b57dSGirish Moodalbail 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1582*8887b57dSGirish Moodalbail 		ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1583*8887b57dSGirish Moodalbail 		    scf_strerror(scf_error()));
1584*8887b57dSGirish Moodalbail 		return (-1);
1585550b6e40SSowmini Varadhan 	}
1586550b6e40SSowmini Varadhan 
1587*8887b57dSGirish Moodalbail 	if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
1588*8887b57dSGirish Moodalbail 	    0, res->sr_pg) != 0) {
1589*8887b57dSGirish Moodalbail 		if ((err = scf_error()) != SCF_ERROR_EXISTS) {
1590550b6e40SSowmini Varadhan 			ipmgmt_log(LOG_WARNING,
1591*8887b57dSGirish Moodalbail 			    "Error adding property group '%s/%s': %s",
1592*8887b57dSGirish Moodalbail 			    pgname, pname, scf_strerror(err));
1593*8887b57dSGirish Moodalbail 			return (-1);
1594*8887b57dSGirish Moodalbail 		}
1595*8887b57dSGirish Moodalbail 		/*
1596*8887b57dSGirish Moodalbail 		 * if the property group already exists, then we get the
1597*8887b57dSGirish Moodalbail 		 * composed view of the property group for the given instance.
1598*8887b57dSGirish Moodalbail 		 */
1599*8887b57dSGirish Moodalbail 		if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
1600*8887b57dSGirish Moodalbail 		    res->sr_pg) != 0) {
1601*8887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Error getting composed view "
1602*8887b57dSGirish Moodalbail 			    "of the property group '%s/%s': %s", pgname, pname,
1603*8887b57dSGirish Moodalbail 			    scf_strerror(scf_error()));
1604*8887b57dSGirish Moodalbail 			return (-1);
1605*8887b57dSGirish Moodalbail 		}
1606550b6e40SSowmini Varadhan 	}
1607550b6e40SSowmini Varadhan 
1608*8887b57dSGirish Moodalbail 	return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
1609*8887b57dSGirish Moodalbail }
1610*8887b57dSGirish Moodalbail 
1611*8887b57dSGirish Moodalbail /*
1612*8887b57dSGirish Moodalbail  * Returns B_TRUE, if the non-global zone is being booted for the first time
1613*8887b57dSGirish Moodalbail  * after being installed. This is required to setup the ipadm data-store for
1614*8887b57dSGirish Moodalbail  * the first boot of the non-global zone. Please see, PSARC 2010/166,
1615*8887b57dSGirish Moodalbail  * for more info.
1616*8887b57dSGirish Moodalbail  *
1617*8887b57dSGirish Moodalbail  * Note that, this API cannot be used to determine first boot post image-update.
1618*8887b57dSGirish Moodalbail  * 'pkg image-update' clones the current BE and the existing value of
1619*8887b57dSGirish Moodalbail  * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
1620*8887b57dSGirish Moodalbail  * to B_TRUE.
1621*8887b57dSGirish Moodalbail  */
1622*8887b57dSGirish Moodalbail boolean_t
1623*8887b57dSGirish Moodalbail ipmgmt_ngz_firstboot_postinstall()
1624*8887b57dSGirish Moodalbail {
1625*8887b57dSGirish Moodalbail 	scf_resources_t	res;
1626*8887b57dSGirish Moodalbail 	boolean_t	bval = B_TRUE;
1627*8887b57dSGirish Moodalbail 	char		*strval;
1628*8887b57dSGirish Moodalbail 
1629*8887b57dSGirish Moodalbail 	/* we always err on the side of caution */
1630*8887b57dSGirish Moodalbail 	if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
1631*8887b57dSGirish Moodalbail 		return (bval);
1632*8887b57dSGirish Moodalbail 
1633*8887b57dSGirish Moodalbail 	if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
1634*8887b57dSGirish Moodalbail 	    SCF_TYPE_ASTRING) > 0) {
1635*8887b57dSGirish Moodalbail 		bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
1636*8887b57dSGirish Moodalbail 		    B_FALSE : B_TRUE);
1637*8887b57dSGirish Moodalbail 	} else {
1638*8887b57dSGirish Moodalbail 		/*
1639*8887b57dSGirish Moodalbail 		 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
1640*8887b57dSGirish Moodalbail 		 * Since we err on the side of caution, we ignore the return
1641*8887b57dSGirish Moodalbail 		 * error and return B_TRUE.
1642*8887b57dSGirish Moodalbail 		 */
1643*8887b57dSGirish Moodalbail 		(void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
1644*8887b57dSGirish Moodalbail 		    IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1645*8887b57dSGirish Moodalbail 	}
1646550b6e40SSowmini Varadhan 	ipmgmt_release_scf_resources(&res);
1647*8887b57dSGirish Moodalbail 	return (bval);
1648*8887b57dSGirish Moodalbail }
1649*8887b57dSGirish Moodalbail 
1650*8887b57dSGirish Moodalbail /*
1651*8887b57dSGirish Moodalbail  * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
1652*8887b57dSGirish Moodalbail  * Today we have to take care of, one case of, upgrading from version 0 to
1653*8887b57dSGirish Moodalbail  * version 1, so we will use boolean_t as means to decide if upgrade is needed
1654*8887b57dSGirish Moodalbail  * or not. Further, the upcoming projects might completely move the flatfile
1655*8887b57dSGirish Moodalbail  * data-store into SCF and hence we shall keep this interface simple.
1656*8887b57dSGirish Moodalbail  */
1657*8887b57dSGirish Moodalbail boolean_t
1658*8887b57dSGirish Moodalbail ipmgmt_needs_upgrade(scf_resources_t *res)
1659*8887b57dSGirish Moodalbail {
1660*8887b57dSGirish Moodalbail 	boolean_t	bval = B_TRUE;
1661*8887b57dSGirish Moodalbail 	int64_t		*verp;
1662*8887b57dSGirish Moodalbail 
1663*8887b57dSGirish Moodalbail 	if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
1664*8887b57dSGirish Moodalbail 	    &verp, SCF_TYPE_INTEGER) > 0) {
1665*8887b57dSGirish Moodalbail 		if (*verp == IPADM_DB_VERSION)
1666*8887b57dSGirish Moodalbail 			bval = B_FALSE;
1667*8887b57dSGirish Moodalbail 	}
1668*8887b57dSGirish Moodalbail 	/*
1669*8887b57dSGirish Moodalbail 	 * 'datastore_version' doesn't exist. Which means that we need to
1670*8887b57dSGirish Moodalbail 	 * upgrade the datastore. We will create 'datastore_version' and set
1671*8887b57dSGirish Moodalbail 	 * the version value to IPADM_DB_VERSION, after we upgrade the file.
1672*8887b57dSGirish Moodalbail 	 */
1673*8887b57dSGirish Moodalbail 	return (bval);
1674*8887b57dSGirish Moodalbail }
1675*8887b57dSGirish Moodalbail 
1676*8887b57dSGirish Moodalbail /*
1677*8887b57dSGirish Moodalbail  * This is called after the successful upgrade of the local data-store. With
1678*8887b57dSGirish Moodalbail  * the data-store upgraded to recent version we don't have to do anything on
1679*8887b57dSGirish Moodalbail  * subsequent reboots.
1680*8887b57dSGirish Moodalbail  */
1681*8887b57dSGirish Moodalbail void
1682*8887b57dSGirish Moodalbail ipmgmt_update_dbver(scf_resources_t *res)
1683*8887b57dSGirish Moodalbail {
1684*8887b57dSGirish Moodalbail 	int64_t		version = IPADM_DB_VERSION;
1685*8887b57dSGirish Moodalbail 
1686*8887b57dSGirish Moodalbail 	(void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1687*8887b57dSGirish Moodalbail 	    IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1688550b6e40SSowmini Varadhan }
1689