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.
24ab618543SJohn Levon  * Copyright 2018 Joyent, Inc.
25c985e172SIgor Kozhukhov  * Copyright 2016 Argo Technologie SA.
26b31320a7SChris Fraire  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
27a73be61aSHans Rosenfeld  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
286e91bba0SGirish Moodalbail  */
296e91bba0SGirish Moodalbail 
306e91bba0SGirish Moodalbail /*
316e91bba0SGirish Moodalbail  * Contains DB walker functions, which are of type `db_wfunc_t';
326e91bba0SGirish Moodalbail  *
336e91bba0SGirish Moodalbail  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
346e91bba0SGirish Moodalbail  *				size_t bufsize, int *errp);
356e91bba0SGirish Moodalbail  *
366e91bba0SGirish Moodalbail  * ipadm_rw_db() walks through the data store, one line at a time and calls
376e91bba0SGirish Moodalbail  * these call back functions with:
386e91bba0SGirish Moodalbail  *	`cbarg'  - callback argument
396e91bba0SGirish Moodalbail  *	`db_nvl' - representing a line from DB in nvlist_t form
406e91bba0SGirish Moodalbail  *	`buf'	 - character buffer to hold modified line
416e91bba0SGirish Moodalbail  *	`bufsize'- size of the buffer
426e91bba0SGirish Moodalbail  *	`errp' - captures any error inside the walker function.
436e91bba0SGirish Moodalbail  *
446e91bba0SGirish Moodalbail  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
456e91bba0SGirish Moodalbail  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
466e91bba0SGirish Moodalbail  * To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
476e91bba0SGirish Moodalbail  * the modified `buf' is written back into DB.
486e91bba0SGirish Moodalbail  *
496e91bba0SGirish Moodalbail  * All the 'read' callback functions, retrieve the information from the DB, by
506e91bba0SGirish Moodalbail  * reading `db_nvl' and then populate the `cbarg'.
516e91bba0SGirish Moodalbail  */
526e91bba0SGirish Moodalbail 
536e91bba0SGirish Moodalbail #include <stdlib.h>
546e91bba0SGirish Moodalbail #include <strings.h>
556e91bba0SGirish Moodalbail #include <errno.h>
566e91bba0SGirish Moodalbail #include <assert.h>
576e91bba0SGirish Moodalbail #include <sys/types.h>
586e91bba0SGirish Moodalbail #include <sys/socket.h>
596e91bba0SGirish Moodalbail #include <netinet/in.h>
606e91bba0SGirish Moodalbail #include <arpa/inet.h>
616e91bba0SGirish Moodalbail #include <unistd.h>
626e91bba0SGirish Moodalbail #include "ipmgmt_impl.h"
638887b57dSGirish Moodalbail 
648887b57dSGirish Moodalbail /* SCF related property group names and property names */
658887b57dSGirish Moodalbail #define	IPMGMTD_APP_PG		"ipmgmtd"
668887b57dSGirish Moodalbail #define	IPMGMTD_PROP_FBD	"first_boot_done"
678887b57dSGirish Moodalbail #define	IPMGMTD_PROP_DBVER	"datastore_version"
688887b57dSGirish Moodalbail #define	IPMGMTD_TRUESTR		"true"
696e91bba0SGirish Moodalbail 
706e91bba0SGirish Moodalbail #define	ATYPE	"_atype"		/* name of the address type nvpair */
716e91bba0SGirish Moodalbail #define	FLAGS	"_flags"		/* name of the flags nvpair */
726e91bba0SGirish Moodalbail 
736e91bba0SGirish Moodalbail /*
746e91bba0SGirish Moodalbail  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
756e91bba0SGirish Moodalbail  * IPADM_ADDR_IPV6_ADDRCONF.
766e91bba0SGirish Moodalbail  */
776e91bba0SGirish Moodalbail #define	IPMGMT_ATYPE_V6ACONF	0x1
786e91bba0SGirish Moodalbail 
796e91bba0SGirish Moodalbail extern pthread_rwlock_t ipmgmt_dbconf_lock;
806e91bba0SGirish Moodalbail 
819b5bf10aSMark Haywood /* signifies whether volatile copy of data store is in use */
829b5bf10aSMark Haywood static boolean_t ipmgmt_rdonly_root = B_FALSE;
839b5bf10aSMark Haywood 
84a73be61aSHans Rosenfeld typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
85a73be61aSHans Rosenfeld 
86a73be61aSHans Rosenfeld static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
87a73be61aSHans Rosenfeld static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
88a73be61aSHans Rosenfeld 
89a73be61aSHans Rosenfeld static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
90a73be61aSHans Rosenfeld 
91a73be61aSHans Rosenfeld typedef struct {
92a73be61aSHans Rosenfeld 	const char	*name;
93a73be61aSHans Rosenfeld 	ipmgmt_if_updater_func_t	*func;
94a73be61aSHans Rosenfeld } ipmgmt_if_updater_ent_t;
95a73be61aSHans Rosenfeld 
96a73be61aSHans Rosenfeld static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
97a73be61aSHans Rosenfeld 	{IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
98a73be61aSHans Rosenfeld 	{IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
99a73be61aSHans Rosenfeld 	{NULL, NULL}
100a73be61aSHans Rosenfeld };
101a73be61aSHans Rosenfeld 
102a73be61aSHans Rosenfeld static ipmgmt_if_updater_ent_t *
ipmgmt_find_if_field_updater(const char * field_name)103a73be61aSHans Rosenfeld ipmgmt_find_if_field_updater(const char *field_name)
104a73be61aSHans Rosenfeld {
105a73be61aSHans Rosenfeld 	int i;
106a73be61aSHans Rosenfeld 
107a73be61aSHans Rosenfeld 	for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
108a73be61aSHans Rosenfeld 		if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
109a73be61aSHans Rosenfeld 			break;
110a73be61aSHans Rosenfeld 		}
111a73be61aSHans Rosenfeld 	}
112a73be61aSHans Rosenfeld 
113a73be61aSHans Rosenfeld 	return (&ipmgmt_if_updater_ent[i]);
114a73be61aSHans Rosenfeld }
115a73be61aSHans Rosenfeld 
116a73be61aSHans Rosenfeld static int
ipmgmt_if_groupmembers_updater(nvlist_t * db_nvl,nvpair_t * member_nvp,uint_t flags)117a73be61aSHans Rosenfeld ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
118a73be61aSHans Rosenfeld     uint_t flags)
119a73be61aSHans Rosenfeld {
120a73be61aSHans Rosenfeld 	char	**members;
121a73be61aSHans Rosenfeld 	char	*member;
122a73be61aSHans Rosenfeld 	char	**out_members;
123a73be61aSHans Rosenfeld 	uint_t  nelem = 0, cnt = 0;
124a73be61aSHans Rosenfeld 	int	err;
125a73be61aSHans Rosenfeld 
126a73be61aSHans Rosenfeld 	if ((err = nvpair_value_string(member_nvp, &member)) != 0)
127a73be61aSHans Rosenfeld 		return (err);
128a73be61aSHans Rosenfeld 
129a73be61aSHans Rosenfeld 	err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
130a73be61aSHans Rosenfeld 	    &members, &nelem);
131a73be61aSHans Rosenfeld 
132a73be61aSHans Rosenfeld 	if (err != 0 && (flags & IPMGMT_REMOVE))
133a73be61aSHans Rosenfeld 		return (ENOENT);
134a73be61aSHans Rosenfeld 
135a73be61aSHans Rosenfeld 	/*
136a73be61aSHans Rosenfeld 	 * Reserve one extra slot for IPMGMT_APPEND.
137a73be61aSHans Rosenfeld 	 * Probably not worth conditionalizing.
138a73be61aSHans Rosenfeld 	 */
139a73be61aSHans Rosenfeld 	out_members = calloc(nelem + 1, sizeof (char *));
140a73be61aSHans Rosenfeld 	if (out_members == NULL)
141a73be61aSHans Rosenfeld 		return (ENOMEM);
142a73be61aSHans Rosenfeld 
143a73be61aSHans Rosenfeld 	while (nelem-- > 0) {
144a73be61aSHans Rosenfeld 		if ((flags & IPMGMT_REMOVE) &&
145a73be61aSHans Rosenfeld 		    (strcmp(member, members[nelem]) == 0))
146a73be61aSHans Rosenfeld 			continue;
147a73be61aSHans Rosenfeld 
148a73be61aSHans Rosenfeld 		if ((out_members[cnt] = strdup(members[nelem])) == NULL) {
149a73be61aSHans Rosenfeld 			err = ENOMEM;
150a73be61aSHans Rosenfeld 			goto fail;
151a73be61aSHans Rosenfeld 		}
152a73be61aSHans Rosenfeld 
153a73be61aSHans Rosenfeld 		cnt++;
154a73be61aSHans Rosenfeld 	}
155a73be61aSHans Rosenfeld 
156a73be61aSHans Rosenfeld 	if (flags & IPMGMT_APPEND) {
157a73be61aSHans Rosenfeld 		if ((out_members[cnt] = strdup(member)) == NULL) {
158a73be61aSHans Rosenfeld 			err = ENOMEM;
159a73be61aSHans Rosenfeld 			goto fail;
160a73be61aSHans Rosenfeld 		}
161a73be61aSHans Rosenfeld 		cnt++;
162a73be61aSHans Rosenfeld 	}
163a73be61aSHans Rosenfeld 
164a73be61aSHans Rosenfeld 	if (cnt == 0) {
165a73be61aSHans Rosenfeld 		err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
166a73be61aSHans Rosenfeld 		    DATA_TYPE_STRING_ARRAY);
167a73be61aSHans Rosenfeld 	} else {
168a73be61aSHans Rosenfeld 		err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
169a73be61aSHans Rosenfeld 		    out_members, cnt);
170a73be61aSHans Rosenfeld 	}
171a73be61aSHans Rosenfeld 
172a73be61aSHans Rosenfeld fail:
173a73be61aSHans Rosenfeld 	while (cnt--)
174a73be61aSHans Rosenfeld 		free(out_members[cnt]);
175a73be61aSHans Rosenfeld 
176a73be61aSHans Rosenfeld 	free(out_members);
177a73be61aSHans Rosenfeld 
178a73be61aSHans Rosenfeld 	return (err);
179a73be61aSHans Rosenfeld }
180a73be61aSHans Rosenfeld 
181a73be61aSHans Rosenfeld static int
ipmgmt_if_family_updater(nvlist_t * db_nvl,nvpair_t * families_nvp,uint_t flags)182a73be61aSHans Rosenfeld ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
183a73be61aSHans Rosenfeld {
184a73be61aSHans Rosenfeld 	uint16_t *families;
185a73be61aSHans Rosenfeld 	uint_t  nelem = 0;
186a73be61aSHans Rosenfeld 	int	err;
187a73be61aSHans Rosenfeld 
188a73be61aSHans Rosenfeld 	if ((err = nvpair_value_uint16_array(families_nvp, &families,
189a73be61aSHans Rosenfeld 	    &nelem)) != 0)
190a73be61aSHans Rosenfeld 		return (err);
191a73be61aSHans Rosenfeld 
192a73be61aSHans Rosenfeld 	return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
193a73be61aSHans Rosenfeld }
194a73be61aSHans Rosenfeld 
195a73be61aSHans Rosenfeld int
ipmgmt_update_family_nvp(nvlist_t * nvl,sa_family_t af,uint_t flags)196a73be61aSHans Rosenfeld ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
197a73be61aSHans Rosenfeld {
198a73be61aSHans Rosenfeld 	uint16_t	*families = NULL;
199a73be61aSHans Rosenfeld 	uint16_t	out_families[2];
200a73be61aSHans Rosenfeld 	uint_t	nelem = 0, cnt;
201a73be61aSHans Rosenfeld 	int	err;
202a73be61aSHans Rosenfeld 
203a73be61aSHans Rosenfeld 	err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
204a73be61aSHans Rosenfeld 	    &families, &nelem);
205a73be61aSHans Rosenfeld 	if (err != 0 && (flags & IPMGMT_REMOVE)) {
206a73be61aSHans Rosenfeld 		return (ENOENT);
207a73be61aSHans Rosenfeld 	}
208a73be61aSHans Rosenfeld 
209a73be61aSHans Rosenfeld 	if (flags & IPMGMT_APPEND) {
210a73be61aSHans Rosenfeld 		if (families != NULL) {
211a73be61aSHans Rosenfeld 			if (nelem == 2 || families[0] == af) {
212a73be61aSHans Rosenfeld 				return (EEXIST);
213a73be61aSHans Rosenfeld 			}
214a73be61aSHans Rosenfeld 			out_families[0] = families[0];
215a73be61aSHans Rosenfeld 			out_families[1] = af;
216a73be61aSHans Rosenfeld 			cnt = 2;
217a73be61aSHans Rosenfeld 		} else {
218a73be61aSHans Rosenfeld 			out_families[0] = af;
219a73be61aSHans Rosenfeld 			cnt = 1;
220a73be61aSHans Rosenfeld 		}
221a73be61aSHans Rosenfeld 	} else {
222a73be61aSHans Rosenfeld 		assert(nelem == 1 || nelem == 2);
223a73be61aSHans Rosenfeld 		cnt = 0;
224a73be61aSHans Rosenfeld 		while (nelem-- > 0) {
225a73be61aSHans Rosenfeld 			if (families[nelem] != af) {
226a73be61aSHans Rosenfeld 				out_families[cnt] = families[nelem];
227a73be61aSHans Rosenfeld 				cnt++;
228a73be61aSHans Rosenfeld 			}
229a73be61aSHans Rosenfeld 		}
230a73be61aSHans Rosenfeld 	}
231a73be61aSHans Rosenfeld 
232a73be61aSHans Rosenfeld 	if (cnt != 0) {
233a73be61aSHans Rosenfeld 		return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
234a73be61aSHans Rosenfeld 		    out_families, cnt));
235a73be61aSHans Rosenfeld 	}
236a73be61aSHans Rosenfeld 	return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
237a73be61aSHans Rosenfeld }
238a73be61aSHans Rosenfeld 
2396e91bba0SGirish Moodalbail /*
2406e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
2416e91bba0SGirish Moodalbail  * in private nvpairs `proto', `ifname' & `aobjname'.
2426e91bba0SGirish Moodalbail  */
2436e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_match(nvlist_t * db_nvl,const char * proto,const char * ifname,const char * aobjname)2446e91bba0SGirish Moodalbail ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
2456e91bba0SGirish Moodalbail     const char *aobjname)
2466e91bba0SGirish Moodalbail {
2476e91bba0SGirish Moodalbail 	char		*db_proto = NULL, *db_ifname = NULL;
2486e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
2496e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
2506e91bba0SGirish Moodalbail 	char		*name;
2516e91bba0SGirish Moodalbail 
2526e91bba0SGirish Moodalbail 	/* walk through db_nvl and retrieve all its private nvpairs */
2536e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
2546e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
2556e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
2566e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
2576e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_proto);
2586e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
2596e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
2606e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
2616e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
2626e91bba0SGirish Moodalbail 	}
2636e91bba0SGirish Moodalbail 
2646e91bba0SGirish Moodalbail 	if (proto != NULL && proto[0] == '\0')
2656e91bba0SGirish Moodalbail 		proto = NULL;
2666e91bba0SGirish Moodalbail 	if (ifname != NULL && ifname[0] == '\0')
2676e91bba0SGirish Moodalbail 		ifname = NULL;
2686e91bba0SGirish Moodalbail 	if (aobjname != NULL && aobjname[0] == '\0')
2696e91bba0SGirish Moodalbail 		aobjname = NULL;
2706e91bba0SGirish Moodalbail 
2716e91bba0SGirish Moodalbail 	if ((proto == NULL && db_proto != NULL) ||
2726e91bba0SGirish Moodalbail 	    (proto != NULL && db_proto == NULL) ||
273c985e172SIgor Kozhukhov 	    (proto != NULL && db_proto != NULL &&
274c985e172SIgor Kozhukhov 	    strcmp(proto, db_proto) != 0)) {
2756e91bba0SGirish Moodalbail 		/* no intersection - different protocols. */
2766e91bba0SGirish Moodalbail 		return (B_FALSE);
2776e91bba0SGirish Moodalbail 	}
2786e91bba0SGirish Moodalbail 	if ((ifname == NULL && db_ifname != NULL) ||
2796e91bba0SGirish Moodalbail 	    (ifname != NULL && db_ifname == NULL) ||
280c985e172SIgor Kozhukhov 	    (ifname != NULL && db_ifname != NULL &&
281c985e172SIgor Kozhukhov 	    strcmp(ifname, db_ifname) != 0)) {
2826e91bba0SGirish Moodalbail 		/* no intersection - different interfaces. */
2836e91bba0SGirish Moodalbail 		return (B_FALSE);
2846e91bba0SGirish Moodalbail 	}
2856e91bba0SGirish Moodalbail 	if ((aobjname == NULL && db_aobjname != NULL) ||
2866e91bba0SGirish Moodalbail 	    (aobjname != NULL && db_aobjname == NULL) ||
287c985e172SIgor Kozhukhov 	    (aobjname != NULL && db_aobjname != NULL &&
288c985e172SIgor Kozhukhov 	    strcmp(aobjname, db_aobjname) != 0)) {
2896e91bba0SGirish Moodalbail 		/* no intersection - different address objects */
2906e91bba0SGirish Moodalbail 		return (B_FALSE);
2916e91bba0SGirish Moodalbail 	}
2926e91bba0SGirish Moodalbail 
2936e91bba0SGirish Moodalbail 	return (B_TRUE);
2946e91bba0SGirish Moodalbail }
2956e91bba0SGirish Moodalbail 
2966e91bba0SGirish Moodalbail /*
2976e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
2986e91bba0SGirish Moodalbail  */
2996e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_intersects(nvlist_t * db_nvl,nvlist_t * in_nvl)3006e91bba0SGirish Moodalbail ipmgmt_nvlist_intersects(nvlist_t *db_nvl, nvlist_t *in_nvl)
3016e91bba0SGirish Moodalbail {
3026e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
3036e91bba0SGirish Moodalbail 	char		*name;
3046e91bba0SGirish Moodalbail 	char		*proto = NULL, *ifname = NULL, *aobjname = NULL;
3056e91bba0SGirish Moodalbail 
3066e91bba0SGirish Moodalbail 	/* walk through in_nvl and retrieve all its private nvpairs */
3076e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
3086e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
3096e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
3106e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
3116e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &proto);
3126e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
3136e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &ifname);
3146e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
3156e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &aobjname);
3166e91bba0SGirish Moodalbail 	}
3176e91bba0SGirish Moodalbail 
3186e91bba0SGirish Moodalbail 	return (ipmgmt_nvlist_match(db_nvl, proto, ifname, aobjname));
3196e91bba0SGirish Moodalbail }
3206e91bba0SGirish Moodalbail 
3216e91bba0SGirish Moodalbail /*
3226e91bba0SGirish Moodalbail  * Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
3236e91bba0SGirish Moodalbail  * in private nvpairs `proto', `ifname' & `aobjname'.
3246e91bba0SGirish Moodalbail  */
3256e91bba0SGirish Moodalbail static boolean_t
ipmgmt_nvlist_contains(nvlist_t * db_nvl,const char * proto,const char * ifname,char * aobjname)3266e91bba0SGirish Moodalbail ipmgmt_nvlist_contains(nvlist_t *db_nvl, const char *proto,
3276e91bba0SGirish Moodalbail     const char *ifname, char *aobjname)
3286e91bba0SGirish Moodalbail {
3296e91bba0SGirish Moodalbail 	char		*db_ifname = NULL, *db_proto = NULL;
3306e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
3316e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
3326e91bba0SGirish Moodalbail 	char		*name;
3336e91bba0SGirish Moodalbail 
3346e91bba0SGirish Moodalbail 	/* walk through db_nvl and retrieve all private nvpairs */
3356e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
3366e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
3376e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
3386e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
3396e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_proto);
3406e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
3416e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
3426e91bba0SGirish Moodalbail 		else if (strcmp(IPADM_NVP_AOBJNAME, name) == 0)
3436e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
3446e91bba0SGirish Moodalbail 	}
3456e91bba0SGirish Moodalbail 
3466e91bba0SGirish Moodalbail 	if (proto != NULL && proto[0] != '\0') {
3476e91bba0SGirish Moodalbail 		if ((db_proto == NULL || strcmp(proto, db_proto) != 0))
3486e91bba0SGirish Moodalbail 			return (B_FALSE);
3496e91bba0SGirish Moodalbail 	}
3506e91bba0SGirish Moodalbail 	if (ifname != NULL && ifname[0] != '\0') {
3516e91bba0SGirish Moodalbail 		if ((db_ifname == NULL || strcmp(ifname, db_ifname) != 0))
3526e91bba0SGirish Moodalbail 			return (B_FALSE);
3536e91bba0SGirish Moodalbail 	}
3546e91bba0SGirish Moodalbail 	if (aobjname != NULL && aobjname[0] != '\0') {
3556e91bba0SGirish Moodalbail 		if ((db_aobjname == NULL || strcmp(aobjname, db_aobjname) != 0))
3566e91bba0SGirish Moodalbail 			return (B_FALSE);
3576e91bba0SGirish Moodalbail 	}
3586e91bba0SGirish Moodalbail 
3596e91bba0SGirish Moodalbail 	return (B_TRUE);
3606e91bba0SGirish Moodalbail }
3616e91bba0SGirish Moodalbail 
3626e91bba0SGirish Moodalbail /*
3636e91bba0SGirish Moodalbail  * Retrieves the property value from the DB. The property whose value is to be
3646e91bba0SGirish Moodalbail  * retrieved is in `pargp->ia_pname'.
3656e91bba0SGirish Moodalbail  */
3666e91bba0SGirish Moodalbail /* ARGSUSED */
3676e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_getprop(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)3686e91bba0SGirish Moodalbail ipmgmt_db_getprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
3696e91bba0SGirish Moodalbail     int *errp)
3706e91bba0SGirish Moodalbail {
3716e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = arg;
3726e91bba0SGirish Moodalbail 	boolean_t		cont = B_TRUE;
3736e91bba0SGirish Moodalbail 	char			*pval;
3746e91bba0SGirish Moodalbail 	int			err = 0;
3756e91bba0SGirish Moodalbail 
3766e91bba0SGirish Moodalbail 	*errp = 0;
3776e91bba0SGirish Moodalbail 
3786e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
3796e91bba0SGirish Moodalbail 	    pargp->ia_ifname, pargp->ia_aobjname))
3806e91bba0SGirish Moodalbail 		return (B_TRUE);
3816e91bba0SGirish Moodalbail 
3826e91bba0SGirish Moodalbail 	if ((err = nvlist_lookup_string(db_nvl, pargp->ia_pname,
3836e91bba0SGirish Moodalbail 	    &pval)) == 0) {
3846e91bba0SGirish Moodalbail 		(void) strlcpy(pargp->ia_pval, pval, sizeof (pargp->ia_pval));
3856e91bba0SGirish Moodalbail 		/*
3866e91bba0SGirish Moodalbail 		 * We have retrieved what we are looking for.
3876e91bba0SGirish Moodalbail 		 * Stop the walker.
3886e91bba0SGirish Moodalbail 		 */
3896e91bba0SGirish Moodalbail 		cont = B_FALSE;
3906e91bba0SGirish Moodalbail 	} else {
3916e91bba0SGirish Moodalbail 		if (err == ENOENT)
3926e91bba0SGirish Moodalbail 			err = 0;
3936e91bba0SGirish Moodalbail 		*errp = err;
3946e91bba0SGirish Moodalbail 	}
3956e91bba0SGirish Moodalbail 
3966e91bba0SGirish Moodalbail 	return (cont);
3976e91bba0SGirish Moodalbail }
3986e91bba0SGirish Moodalbail 
3996e91bba0SGirish Moodalbail /*
4006e91bba0SGirish Moodalbail  * Removes the property value from the DB. The property whose value is to be
4016e91bba0SGirish Moodalbail  * removed is in `pargp->ia_pname'.
4026e91bba0SGirish Moodalbail  */
4036e91bba0SGirish Moodalbail /* ARGSUSED */
4046e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetprop(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)4056e91bba0SGirish Moodalbail ipmgmt_db_resetprop(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
4066e91bba0SGirish Moodalbail     int *errp)
4076e91bba0SGirish Moodalbail {
4086e91bba0SGirish Moodalbail 	ipmgmt_prop_arg_t	*pargp = arg;
4096e91bba0SGirish Moodalbail 
4106e91bba0SGirish Moodalbail 	*errp = 0;
4116e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, pargp->ia_module,
4126e91bba0SGirish Moodalbail 	    pargp->ia_ifname, pargp->ia_aobjname))
4136e91bba0SGirish Moodalbail 		return (B_TRUE);
4146e91bba0SGirish Moodalbail 
4156e91bba0SGirish Moodalbail 	if (!nvlist_exists(db_nvl, pargp->ia_pname))
4166e91bba0SGirish Moodalbail 		return (B_TRUE);
4176e91bba0SGirish Moodalbail 
4186e91bba0SGirish Moodalbail 	/*
4196e91bba0SGirish Moodalbail 	 * We found the property in the DB. If IPMGMT_REMOVE is not set then
4206e91bba0SGirish Moodalbail 	 * delete the entry from the db. If it is set, then the property is a
4216e91bba0SGirish Moodalbail 	 * multi-valued property so just remove the specified values from DB.
4226e91bba0SGirish Moodalbail 	 */
4236e91bba0SGirish Moodalbail 	if (pargp->ia_flags & IPMGMT_REMOVE) {
4246e91bba0SGirish Moodalbail 		char	*dbpval = NULL;
4256e91bba0SGirish Moodalbail 		char	*inpval = pargp->ia_pval;
4266e91bba0SGirish Moodalbail 		char	pval[MAXPROPVALLEN];
4276e91bba0SGirish Moodalbail 		char	*val, *lasts;
4286e91bba0SGirish Moodalbail 
4296e91bba0SGirish Moodalbail 		*errp = nvlist_lookup_string(db_nvl, pargp->ia_pname, &dbpval);
4306e91bba0SGirish Moodalbail 		if (*errp != 0)
4316e91bba0SGirish Moodalbail 			return (B_FALSE);
4326e91bba0SGirish Moodalbail 
4336e91bba0SGirish Moodalbail 		/*
4346e91bba0SGirish Moodalbail 		 * multi-valued properties are represented as comma separated
4356e91bba0SGirish Moodalbail 		 * values. Use string tokenizer functions to split them and
4366e91bba0SGirish Moodalbail 		 * search for the value to be removed.
4376e91bba0SGirish Moodalbail 		 */
4386e91bba0SGirish Moodalbail 		bzero(pval, sizeof (pval));
4396e91bba0SGirish Moodalbail 		if ((val = strtok_r(dbpval, ",", &lasts)) != NULL) {
4406e91bba0SGirish Moodalbail 			if (strcmp(val, inpval) != 0)
4416e91bba0SGirish Moodalbail 				(void) strlcat(pval, val, MAXPROPVALLEN);
4426e91bba0SGirish Moodalbail 			while ((val = strtok_r(NULL, ",", &lasts)) != NULL) {
4436e91bba0SGirish Moodalbail 				if (strcmp(val, inpval) != 0) {
4446e91bba0SGirish Moodalbail 					if (pval[0] != '\0')
4456e91bba0SGirish Moodalbail 						(void) strlcat(pval, ",",
4466e91bba0SGirish Moodalbail 						    MAXPROPVALLEN);
4476e91bba0SGirish Moodalbail 					(void) strlcat(pval, val,
4486e91bba0SGirish Moodalbail 					    MAXPROPVALLEN);
4496e91bba0SGirish Moodalbail 				}
4506e91bba0SGirish Moodalbail 			}
4516e91bba0SGirish Moodalbail 		} else {
4526e91bba0SGirish Moodalbail 			if (strcmp(dbpval, inpval) != 0)
4536e91bba0SGirish Moodalbail 				*errp = ENOENT;
4546e91bba0SGirish Moodalbail 			else
4556e91bba0SGirish Moodalbail 				buf[0] =  '\0';
4566e91bba0SGirish Moodalbail 			return (B_FALSE);
4576e91bba0SGirish Moodalbail 		}
4586e91bba0SGirish Moodalbail 		*errp = nvlist_add_string(db_nvl, pargp->ia_pname, pval);
4596e91bba0SGirish Moodalbail 		if (*errp != 0)
4606e91bba0SGirish Moodalbail 			return (B_FALSE);
4616e91bba0SGirish Moodalbail 
4626e91bba0SGirish Moodalbail 		(void) memset(buf, 0, buflen);
4636e91bba0SGirish Moodalbail 		if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
4646e91bba0SGirish Moodalbail 			/* buffer overflow */
4656e91bba0SGirish Moodalbail 			*errp = ENOBUFS;
4666e91bba0SGirish Moodalbail 		}
4676e91bba0SGirish Moodalbail 	} else {
4686e91bba0SGirish Moodalbail 		buf[0] = '\0';
4696e91bba0SGirish Moodalbail 	}
4706e91bba0SGirish Moodalbail 
4716e91bba0SGirish Moodalbail 	/* stop the search */
4726e91bba0SGirish Moodalbail 	return (B_FALSE);
4736e91bba0SGirish Moodalbail }
4746e91bba0SGirish Moodalbail 
4756e91bba0SGirish Moodalbail /*
4766e91bba0SGirish Moodalbail  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
4776e91bba0SGirish Moodalbail  * found, when one of the following occurs first.
4786e91bba0SGirish Moodalbail  * - the input aobjname matches the db aobjname. Return the db address.
4796e91bba0SGirish Moodalbail  * - the input interface matches the db interface. Return all the
4806e91bba0SGirish Moodalbail  *   matching db lines with addresses.
4816e91bba0SGirish Moodalbail  */
4826e91bba0SGirish Moodalbail /* ARGSUSED */
4836e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_getaddr(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)4846e91bba0SGirish Moodalbail ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
4856e91bba0SGirish Moodalbail     int *errp)
4866e91bba0SGirish Moodalbail {
487a73be61aSHans Rosenfeld 	ipmgmt_get_cbarg_t	*cbarg = arg;
4886e91bba0SGirish Moodalbail 	char		*db_aobjname = NULL;
4896e91bba0SGirish Moodalbail 	char		*db_ifname = NULL;
4906e91bba0SGirish Moodalbail 	nvlist_t	*db_addr = NULL;
4916e91bba0SGirish Moodalbail 	char		name[IPMGMT_STRSIZE];
4926e91bba0SGirish Moodalbail 	nvpair_t	*nvp;
4936e91bba0SGirish Moodalbail 	boolean_t	add_nvl = B_FALSE;
4946e91bba0SGirish Moodalbail 
4956e91bba0SGirish Moodalbail 	/* Parse db nvlist */
4966e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
4976e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
4986e91bba0SGirish Moodalbail 		if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
4996e91bba0SGirish Moodalbail 			(void) nvpair_value_nvlist(nvp, &db_addr);
5006e91bba0SGirish Moodalbail 		else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
5016e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_ifname);
5026e91bba0SGirish Moodalbail 		else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
5036e91bba0SGirish Moodalbail 			(void) nvpair_value_string(nvp, &db_aobjname);
5046e91bba0SGirish Moodalbail 	}
5056e91bba0SGirish Moodalbail 
5066e91bba0SGirish Moodalbail 	if (db_aobjname == NULL) /* Not an address */
5076e91bba0SGirish Moodalbail 		return (B_TRUE);
5086e91bba0SGirish Moodalbail 
5096e91bba0SGirish Moodalbail 	/* Check for a match between the aobjnames or the interface name */
5106e91bba0SGirish Moodalbail 	if (cbarg->cb_aobjname[0] != '\0') {
5116e91bba0SGirish Moodalbail 		if (strcmp(cbarg->cb_aobjname, db_aobjname) == 0)
5126e91bba0SGirish Moodalbail 			add_nvl = B_TRUE;
5136e91bba0SGirish Moodalbail 	} else if (cbarg->cb_ifname[0] != '\0') {
5146e91bba0SGirish Moodalbail 		if (strcmp(cbarg->cb_ifname, db_ifname) == 0)
5156e91bba0SGirish Moodalbail 			add_nvl = B_TRUE;
5166e91bba0SGirish Moodalbail 	} else {
5176e91bba0SGirish Moodalbail 		add_nvl = B_TRUE;
5186e91bba0SGirish Moodalbail 	}
5196e91bba0SGirish Moodalbail 
5206e91bba0SGirish Moodalbail 	if (add_nvl) {
5216e91bba0SGirish Moodalbail 		(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
5226e91bba0SGirish Moodalbail 		    cbarg->cb_ocnt);
5236e91bba0SGirish Moodalbail 		*errp = nvlist_add_nvlist(cbarg->cb_onvl, name, db_nvl);
5246e91bba0SGirish Moodalbail 		if (*errp == 0)
5256e91bba0SGirish Moodalbail 			cbarg->cb_ocnt++;
5266e91bba0SGirish Moodalbail 	}
5276e91bba0SGirish Moodalbail 	return (B_TRUE);
5286e91bba0SGirish Moodalbail }
5296e91bba0SGirish Moodalbail 
5309b5bf10aSMark Haywood /*
5319b5bf10aSMark Haywood  * This function only gets called if a volatile filesystem version
5329b5bf10aSMark Haywood  * of the configuration file has been created. This only happens in the
5339b5bf10aSMark Haywood  * extremely rare case that a request has been made to update the configuration
5349b5bf10aSMark Haywood  * file at boottime while the root filesystem was read-only. This is
5359b5bf10aSMark Haywood  * really a rare occurrence now that we don't support UFS root filesystems
5369b5bf10aSMark Haywood  * any longer. This function will periodically attempt to write the
5379b5bf10aSMark Haywood  * configuration back to its location on the root filesystem. Success
5389b5bf10aSMark Haywood  * will indicate that the filesystem is no longer read-only.
5399b5bf10aSMark Haywood  */
5409b5bf10aSMark Haywood /* ARGSUSED */
5419b5bf10aSMark Haywood static void *
ipmgmt_db_restore_thread(void * arg)5429b5bf10aSMark Haywood ipmgmt_db_restore_thread(void *arg)
5439b5bf10aSMark Haywood {
5449b5bf10aSMark Haywood 	int err;
5459b5bf10aSMark Haywood 
5469b5bf10aSMark Haywood 	for (;;) {
5479b5bf10aSMark Haywood 		(void) sleep(5);
5489b5bf10aSMark Haywood 		(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
5499b5bf10aSMark Haywood 		if (!ipmgmt_rdonly_root)
5509b5bf10aSMark Haywood 			break;
5519b5bf10aSMark Haywood 		err = ipmgmt_cpfile(IPADM_VOL_DB_FILE, IPADM_DB_FILE, B_FALSE);
5529b5bf10aSMark Haywood 		if (err == 0) {
5539b5bf10aSMark Haywood 			ipmgmt_rdonly_root = B_FALSE;
5549b5bf10aSMark Haywood 			break;
5559b5bf10aSMark Haywood 		}
5569b5bf10aSMark Haywood 		(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
5579b5bf10aSMark Haywood 	}
5589b5bf10aSMark Haywood 	(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
5599b5bf10aSMark Haywood 	return (NULL);
5609b5bf10aSMark Haywood }
5619b5bf10aSMark Haywood 
5626e91bba0SGirish Moodalbail /*
5636e91bba0SGirish Moodalbail  * This function takes the appropriate lock, read or write, based on the
5649b5bf10aSMark Haywood  * `db_op' and then calls DB walker ipadm_rw_db(). The code is complicated
5659b5bf10aSMark Haywood  * by the fact that we are not always guaranteed to have a writable root
5669b5bf10aSMark Haywood  * filesystem since it is possible that we are reading or writing during
5679b5bf10aSMark Haywood  * bootime while the root filesystem is still read-only. This is, by far,
5689b5bf10aSMark Haywood  * the exception case. Normally, this function will be called when the
5699b5bf10aSMark Haywood  * root filesystem is writable. In the unusual case where this is not
5709b5bf10aSMark Haywood  * true, the configuration file is copied to the volatile file system
5719b5bf10aSMark Haywood  * and is updated there until the root filesystem becomes writable. At
5729b5bf10aSMark Haywood  * that time the file will be moved back to its proper location by
5739b5bf10aSMark Haywood  * ipmgmt_db_restore_thread().
5746e91bba0SGirish Moodalbail  */
5756e91bba0SGirish Moodalbail extern int
ipmgmt_db_walk(db_wfunc_t * db_walk_func,void * db_warg,ipadm_db_op_t db_op)5766e91bba0SGirish Moodalbail ipmgmt_db_walk(db_wfunc_t *db_walk_func, void *db_warg, ipadm_db_op_t db_op)
5776e91bba0SGirish Moodalbail {
5786e91bba0SGirish Moodalbail 	int		err;
5796e91bba0SGirish Moodalbail 	boolean_t	writeop;
5806e91bba0SGirish Moodalbail 	mode_t		mode;
5819b5bf10aSMark Haywood 	pthread_t	tid;
5828887b57dSGirish Moodalbail 	pthread_attr_t	attr;
5836e91bba0SGirish Moodalbail 
5846e91bba0SGirish Moodalbail 	writeop = (db_op != IPADM_DB_READ);
5856e91bba0SGirish Moodalbail 	if (writeop) {
5866e91bba0SGirish Moodalbail 		(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
5876e91bba0SGirish Moodalbail 		mode = IPADM_FILE_MODE;
5886e91bba0SGirish Moodalbail 	} else {
5896e91bba0SGirish Moodalbail 		(void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
5906e91bba0SGirish Moodalbail 		mode = 0;
5916e91bba0SGirish Moodalbail 	}
5926e91bba0SGirish Moodalbail 
5939b5bf10aSMark Haywood 	/*
5949b5bf10aSMark Haywood 	 * Did a previous write attempt fail? If so, don't even try to
5959b5bf10aSMark Haywood 	 * read/write to IPADM_DB_FILE.
5969b5bf10aSMark Haywood 	 */
5979b5bf10aSMark Haywood 	if (!ipmgmt_rdonly_root) {
5989b5bf10aSMark Haywood 		err = ipadm_rw_db(db_walk_func, db_warg, IPADM_DB_FILE,
5999b5bf10aSMark Haywood 		    mode, db_op);
6009b5bf10aSMark Haywood 		if (err != EROFS)
6019b5bf10aSMark Haywood 			goto done;
6029b5bf10aSMark Haywood 	}
6039b5bf10aSMark Haywood 
6049b5bf10aSMark Haywood 	/*
6059b5bf10aSMark Haywood 	 * If we haven't already copied the file to the volatile
6069b5bf10aSMark Haywood 	 * file system, do so. This should only happen on a failed
6079b5bf10aSMark Haywood 	 * writeop(i.e., we have acquired the write lock above).
6089b5bf10aSMark Haywood 	 */
6099b5bf10aSMark Haywood 	if (access(IPADM_VOL_DB_FILE, F_OK) != 0) {
6109b5bf10aSMark Haywood 		assert(writeop);
6119b5bf10aSMark Haywood 		err = ipmgmt_cpfile(IPADM_DB_FILE, IPADM_VOL_DB_FILE, B_TRUE);
6129b5bf10aSMark Haywood 		if (err != 0)
6139b5bf10aSMark Haywood 			goto done;
6148887b57dSGirish Moodalbail 		(void) pthread_attr_init(&attr);
6158887b57dSGirish Moodalbail 		(void) pthread_attr_setdetachstate(&attr,
6168887b57dSGirish Moodalbail 		    PTHREAD_CREATE_DETACHED);
617ab618543SJohn Levon 		(void) pthread_attr_setname_np(&attr, "db_restore");
6188887b57dSGirish Moodalbail 		err = pthread_create(&tid, &attr, ipmgmt_db_restore_thread,
6199b5bf10aSMark Haywood 		    NULL);
6208887b57dSGirish Moodalbail 		(void) pthread_attr_destroy(&attr);
6219b5bf10aSMark Haywood 		if (err != 0) {
6229b5bf10aSMark Haywood 			(void) unlink(IPADM_VOL_DB_FILE);
6239b5bf10aSMark Haywood 			goto done;
6249b5bf10aSMark Haywood 		}
6259b5bf10aSMark Haywood 		ipmgmt_rdonly_root = B_TRUE;
6269b5bf10aSMark Haywood 	}
6279b5bf10aSMark Haywood 
6289b5bf10aSMark Haywood 	/*
6299b5bf10aSMark Haywood 	 * Read/write from the volatile copy.
6309b5bf10aSMark Haywood 	 */
6319b5bf10aSMark Haywood 	err = ipadm_rw_db(db_walk_func, db_warg, IPADM_VOL_DB_FILE,
6329b5bf10aSMark Haywood 	    mode, db_op);
6339b5bf10aSMark Haywood done:
6346e91bba0SGirish Moodalbail 	(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
6356e91bba0SGirish Moodalbail 	return (err);
6366e91bba0SGirish Moodalbail }
6376e91bba0SGirish Moodalbail 
6386e91bba0SGirish Moodalbail /*
6396e91bba0SGirish Moodalbail  * Used to add an entry towards the end of DB. It just returns B_TRUE for
6406e91bba0SGirish Moodalbail  * every line of the DB. When we reach the end, ipadm_rw_db() adds the
6416e91bba0SGirish Moodalbail  * line at the end.
6426e91bba0SGirish Moodalbail  */
6436e91bba0SGirish Moodalbail /* ARGSUSED */
6446e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_add(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)6456e91bba0SGirish Moodalbail ipmgmt_db_add(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen, int *errp)
6466e91bba0SGirish Moodalbail {
6476e91bba0SGirish Moodalbail 	return (B_TRUE);
6486e91bba0SGirish Moodalbail }
6496e91bba0SGirish Moodalbail 
6506e91bba0SGirish Moodalbail /*
6516e91bba0SGirish Moodalbail  * This function is used to update or create an entry in DB. The nvlist_t,
6526e91bba0SGirish Moodalbail  * `in_nvl', represents the line we are looking for. Once we ensure the right
6536e91bba0SGirish Moodalbail  * line from DB, we update that entry.
6546e91bba0SGirish Moodalbail  */
6556e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_update(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)6566e91bba0SGirish Moodalbail ipmgmt_db_update(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
6576e91bba0SGirish Moodalbail     int *errp)
6586e91bba0SGirish Moodalbail {
6596e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	*cb = arg;
6606e91bba0SGirish Moodalbail 	uint_t			flags = cb->dbw_flags;
6616e91bba0SGirish Moodalbail 	nvlist_t		*in_nvl = cb->dbw_nvl;
6626e91bba0SGirish Moodalbail 	nvpair_t		*nvp;
6636e91bba0SGirish Moodalbail 	char			*name, *instrval = NULL, *dbstrval = NULL;
6646e91bba0SGirish Moodalbail 	char			pval[MAXPROPVALLEN];
6656e91bba0SGirish Moodalbail 
6668887b57dSGirish Moodalbail 	*errp = 0;
6676e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
6686e91bba0SGirish Moodalbail 		return (B_TRUE);
6696e91bba0SGirish Moodalbail 
6706e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
6716e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
6726e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
6736e91bba0SGirish Moodalbail 		if (!IPADM_PRIV_NVP(name) && nvlist_exists(db_nvl, name))
6746e91bba0SGirish Moodalbail 			break;
6756e91bba0SGirish Moodalbail 	}
6766e91bba0SGirish Moodalbail 
6776e91bba0SGirish Moodalbail 	if (nvp == NULL)
6786e91bba0SGirish Moodalbail 		return (B_TRUE);
6796e91bba0SGirish Moodalbail 
6806e91bba0SGirish Moodalbail 	assert(nvpair_type(nvp) == DATA_TYPE_STRING);
6816e91bba0SGirish Moodalbail 
6826e91bba0SGirish Moodalbail 	if ((*errp = nvpair_value_string(nvp, &instrval)) != 0)
6836e91bba0SGirish Moodalbail 		return (B_FALSE);
6846e91bba0SGirish Moodalbail 
6856e91bba0SGirish Moodalbail 	/*
6866e91bba0SGirish Moodalbail 	 * If IPMGMT_APPEND is set then we are dealing with multi-valued
6876e91bba0SGirish Moodalbail 	 * properties. We append to the entry from the db, with the new value.
6886e91bba0SGirish Moodalbail 	 */
6896e91bba0SGirish Moodalbail 	if (flags & IPMGMT_APPEND) {
6906e91bba0SGirish Moodalbail 		if ((*errp = nvlist_lookup_string(db_nvl, name,
6916e91bba0SGirish Moodalbail 		    &dbstrval)) != 0)
6926e91bba0SGirish Moodalbail 			return (B_FALSE);
6936e91bba0SGirish Moodalbail 		(void) snprintf(pval, MAXPROPVALLEN, "%s,%s", dbstrval,
6946e91bba0SGirish Moodalbail 		    instrval);
6956e91bba0SGirish Moodalbail 		if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
6966e91bba0SGirish Moodalbail 			return (B_FALSE);
6976e91bba0SGirish Moodalbail 	} else {
6986e91bba0SGirish Moodalbail 		/* case	of in-line update of a db entry */
6996e91bba0SGirish Moodalbail 		if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
7006e91bba0SGirish Moodalbail 			return (B_FALSE);
7016e91bba0SGirish Moodalbail 	}
7026e91bba0SGirish Moodalbail 
7036e91bba0SGirish Moodalbail 	(void) memset(buf, 0, buflen);
7046e91bba0SGirish Moodalbail 	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
7056e91bba0SGirish Moodalbail 		/* buffer overflow */
7066e91bba0SGirish Moodalbail 		*errp = ENOBUFS;
7076e91bba0SGirish Moodalbail 	}
7086e91bba0SGirish Moodalbail 
7096e91bba0SGirish Moodalbail 	/* we updated the DB entry, so do not continue */
7106e91bba0SGirish Moodalbail 	return (B_FALSE);
7116e91bba0SGirish Moodalbail }
7126e91bba0SGirish Moodalbail 
7136e91bba0SGirish Moodalbail /*
714a73be61aSHans Rosenfeld  * This function is used to update a DB line that describes
715a73be61aSHans Rosenfeld  * an interface, its family and group interface
716a73be61aSHans Rosenfeld  *
7176e91bba0SGirish Moodalbail  */
7186e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_update_if(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)719a73be61aSHans Rosenfeld ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
7206e91bba0SGirish Moodalbail     int *errp)
7216e91bba0SGirish Moodalbail {
722a73be61aSHans Rosenfeld 	ipadm_dbwrite_cbarg_t *cb = arg;
723a73be61aSHans Rosenfeld 	ipmgmt_if_updater_ent_t *updater;
724a73be61aSHans Rosenfeld 	nvlist_t	*in_nvl = cb->dbw_nvl;
725a73be61aSHans Rosenfeld 	uint_t		flags = cb->dbw_flags;
726a73be61aSHans Rosenfeld 	nvpair_t	*nvp;
727a73be61aSHans Rosenfeld 	char		*name;
728a73be61aSHans Rosenfeld 	char		*db_ifname;
729a73be61aSHans Rosenfeld 	char		*gifname = NULL;
730a73be61aSHans Rosenfeld 	char		*mifname = NULL;
7316e91bba0SGirish Moodalbail 
7326e91bba0SGirish Moodalbail 	*errp = 0;
733a73be61aSHans Rosenfeld 
734a73be61aSHans Rosenfeld 	/* Only one flag */
735a73be61aSHans Rosenfeld 	if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
736a73be61aSHans Rosenfeld 	    ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
737a73be61aSHans Rosenfeld 		*errp = EINVAL;
738a73be61aSHans Rosenfeld 		return (B_FALSE);
739a73be61aSHans Rosenfeld 	}
740a73be61aSHans Rosenfeld 
741a73be61aSHans Rosenfeld 	if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
7426e91bba0SGirish Moodalbail 		return (B_TRUE);
743a73be61aSHans Rosenfeld 
744a73be61aSHans Rosenfeld 	if (nvlist_exists(db_nvl, IPADM_NVP_IFCLASS) &&
745a73be61aSHans Rosenfeld 	    nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
746a73be61aSHans Rosenfeld 	    nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
747a73be61aSHans Rosenfeld 	    nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &mifname) == 0 &&
748a73be61aSHans Rosenfeld 	    strcmp(db_ifname, mifname) == 0) {
749a73be61aSHans Rosenfeld 		if (flags & IPMGMT_APPEND) {
750a73be61aSHans Rosenfeld 			if ((*errp = nvlist_add_string(db_nvl,
751a73be61aSHans Rosenfeld 			    IPADM_NVP_GIFNAME, gifname)) != 0)
752a73be61aSHans Rosenfeld 				return (B_FALSE);
753a73be61aSHans Rosenfeld 		} else {
754a73be61aSHans Rosenfeld 			if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
755a73be61aSHans Rosenfeld 			    DATA_TYPE_STRING)) != 0)
756a73be61aSHans Rosenfeld 				return (B_FALSE);
757a73be61aSHans Rosenfeld 		}
758a73be61aSHans Rosenfeld 		cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
759a73be61aSHans Rosenfeld 		goto done;
7606e91bba0SGirish Moodalbail 	}
761a73be61aSHans Rosenfeld 
762a73be61aSHans Rosenfeld 	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
763a73be61aSHans Rosenfeld 		return (B_TRUE);
764a73be61aSHans Rosenfeld 
765a73be61aSHans Rosenfeld 	for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
766a73be61aSHans Rosenfeld 	    nvp = nvlist_next_nvpair(in_nvl, nvp)) {
767a73be61aSHans Rosenfeld 		name = nvpair_name(nvp);
768a73be61aSHans Rosenfeld 		if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
769a73be61aSHans Rosenfeld 		    strcmp(name, IPADM_NVP_MIFNAMES) != 0)
770a73be61aSHans Rosenfeld 			continue;
771a73be61aSHans Rosenfeld 
772a73be61aSHans Rosenfeld 		updater = ipmgmt_find_if_field_updater(name);
773a73be61aSHans Rosenfeld 		assert(updater != NULL);
774a73be61aSHans Rosenfeld 		*errp = (*updater->func)(db_nvl, nvp, flags);
775a73be61aSHans Rosenfeld 		if (*errp != 0)
776a73be61aSHans Rosenfeld 			return (B_FALSE);
7776e91bba0SGirish Moodalbail 	}
7786e91bba0SGirish Moodalbail 
779a73be61aSHans Rosenfeld 	cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
780a73be61aSHans Rosenfeld 
781a73be61aSHans Rosenfeld done:
782a73be61aSHans Rosenfeld 	(void) memset(buf, 0, buflen);
783a73be61aSHans Rosenfeld 	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
784a73be61aSHans Rosenfeld 		*errp = EOVERFLOW;
785a73be61aSHans Rosenfeld 		return (B_FALSE);
7866e91bba0SGirish Moodalbail 	}
7876e91bba0SGirish Moodalbail 
788a73be61aSHans Rosenfeld 	/* we finished all operations, so do not continue */
789a73be61aSHans Rosenfeld 	if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
790a73be61aSHans Rosenfeld 		return (B_FALSE);
791a73be61aSHans Rosenfeld 
792a73be61aSHans Rosenfeld 	return (B_TRUE);
793a73be61aSHans Rosenfeld }
794a73be61aSHans Rosenfeld 
795a73be61aSHans Rosenfeld /*
796a73be61aSHans Rosenfeld  * For the given `cbarg->cb_ifname' interface, retrieve the nvlist that
797a73be61aSHans Rosenfeld  * represents the persistent interface information.
798a73be61aSHans Rosenfeld  * The nvlist contains:
799a73be61aSHans Rosenfeld  *      IPADM_NVP_IFNAME
800a73be61aSHans Rosenfeld  *      IPADM_NVP_FAMILIES
801a73be61aSHans Rosenfeld  *      IPADM_NVP_IF_CLASS
802a73be61aSHans Rosenfeld  *
803a73be61aSHans Rosenfeld  * (used in 'ipadm show-if')
804a73be61aSHans Rosenfeld  */
805a73be61aSHans Rosenfeld /* ARGSUSED */
806a73be61aSHans Rosenfeld boolean_t
ipmgmt_db_getif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)807a73be61aSHans Rosenfeld ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
808a73be61aSHans Rosenfeld     int *errp)
809a73be61aSHans Rosenfeld {
810a73be61aSHans Rosenfeld 	ipmgmt_get_cbarg_t *cbarg = arg;
811a73be61aSHans Rosenfeld 	char		*ifname = cbarg->cb_ifname;
812a73be61aSHans Rosenfeld 	nvpair_t	*nvp;
813a73be61aSHans Rosenfeld 	char		*db_ifname = NULL;
814a73be61aSHans Rosenfeld 	boolean_t	families = B_FALSE;
815a73be61aSHans Rosenfeld 
816a73be61aSHans Rosenfeld 	/* Parse db nvlist */
817a73be61aSHans Rosenfeld 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
818a73be61aSHans Rosenfeld 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
819a73be61aSHans Rosenfeld 		if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) {
820a73be61aSHans Rosenfeld 			(void) nvpair_value_string(nvp, &db_ifname);
821a73be61aSHans Rosenfeld 		} else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) {
822a73be61aSHans Rosenfeld 			families = B_TRUE;
823a73be61aSHans Rosenfeld 		}
8246e91bba0SGirish Moodalbail 	}
8256e91bba0SGirish Moodalbail 
826a73be61aSHans Rosenfeld 	if (db_ifname == NULL || !families)
827a73be61aSHans Rosenfeld 		return (B_TRUE);
828a73be61aSHans Rosenfeld 
829a73be61aSHans Rosenfeld 	if (ifname != NULL && ifname[0] != '\0' &&
830a73be61aSHans Rosenfeld 	    strcmp(ifname, db_ifname) != 0)
831a73be61aSHans Rosenfeld 		return (B_TRUE);
832a73be61aSHans Rosenfeld 
833a73be61aSHans Rosenfeld 	*errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
834a73be61aSHans Rosenfeld 	if (*errp == 0)
835a73be61aSHans Rosenfeld 		cbarg->cb_ocnt++;
836a73be61aSHans Rosenfeld 
837a73be61aSHans Rosenfeld 	if (ifname != NULL && ifname[0] != '\0')
8386e91bba0SGirish Moodalbail 		return (B_FALSE);
8396e91bba0SGirish Moodalbail 
8406e91bba0SGirish Moodalbail 	return (B_TRUE);
8416e91bba0SGirish Moodalbail }
8426e91bba0SGirish Moodalbail 
8436e91bba0SGirish Moodalbail /*
8446e91bba0SGirish Moodalbail  * Deletes those entries from the database for which interface name
8456e91bba0SGirish Moodalbail  * matches with the given `cbarg->cb_ifname'
8466e91bba0SGirish Moodalbail  */
8476e91bba0SGirish Moodalbail /* ARGSUSED */
8486e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)8496e91bba0SGirish Moodalbail ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
8506e91bba0SGirish Moodalbail     int *errp)
8516e91bba0SGirish Moodalbail {
8526e91bba0SGirish Moodalbail 	ipmgmt_if_cbarg_t *cbarg = arg;
8536e91bba0SGirish Moodalbail 	boolean_t	isv6 = (cbarg->cb_family == AF_INET6);
8546e91bba0SGirish Moodalbail 	char		*ifname = cbarg->cb_ifname;
8556e91bba0SGirish Moodalbail 	char		*modstr = NULL;
8566e91bba0SGirish Moodalbail 	char		*aobjname;
8576e91bba0SGirish Moodalbail 	uint_t		proto;
8586e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t *head;
8596e91bba0SGirish Moodalbail 	boolean_t	aobjfound = B_FALSE;
8606e91bba0SGirish Moodalbail 
8616e91bba0SGirish Moodalbail 	*errp = 0;
8626e91bba0SGirish Moodalbail 
8636e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
8646e91bba0SGirish Moodalbail 		return (B_TRUE);
8656e91bba0SGirish Moodalbail 
866a73be61aSHans Rosenfeld 	if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
867a73be61aSHans Rosenfeld 
868a73be61aSHans Rosenfeld 		if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
869a73be61aSHans Rosenfeld 		    IPMGMT_REMOVE)) != 0) {
870a73be61aSHans Rosenfeld 			return (B_FALSE);
871a73be61aSHans Rosenfeld 		}
872a73be61aSHans Rosenfeld 
873a73be61aSHans Rosenfeld 		if (cbarg->cb_family == AF_INET) {
874a73be61aSHans Rosenfeld 			cbarg->cb_ipv4exists = B_FALSE;
875a73be61aSHans Rosenfeld 		} else {
876a73be61aSHans Rosenfeld 			assert(cbarg->cb_family == AF_INET6);
877a73be61aSHans Rosenfeld 			cbarg->cb_ipv6exists = B_FALSE;
878a73be61aSHans Rosenfeld 		}
879a73be61aSHans Rosenfeld 		if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
880a73be61aSHans Rosenfeld 			cbarg->cb_ipv4exists = B_FALSE;
881a73be61aSHans Rosenfeld 			cbarg->cb_ipv6exists = B_FALSE;
8826e91bba0SGirish Moodalbail 			goto delete;
883a73be61aSHans Rosenfeld 		}
884a73be61aSHans Rosenfeld 		/* Otherwise need to reconstruct this string */
885a73be61aSHans Rosenfeld 		(void) memset(buf, 0, buflen);
886a73be61aSHans Rosenfeld 		if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
887a73be61aSHans Rosenfeld 			/* buffer overflow */
888a73be61aSHans Rosenfeld 			*errp = EOVERFLOW;
889a73be61aSHans Rosenfeld 			return (B_FALSE);
890a73be61aSHans Rosenfeld 		}
8916e91bba0SGirish Moodalbail 		return (B_TRUE);
8926e91bba0SGirish Moodalbail 	}
8936e91bba0SGirish Moodalbail 
8946e91bba0SGirish Moodalbail 	/* Reset all the interface configurations for 'ifname' */
8956e91bba0SGirish Moodalbail 	if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
8966e91bba0SGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
8976e91bba0SGirish Moodalbail 		goto delete;
8986e91bba0SGirish Moodalbail 	}
8996e91bba0SGirish Moodalbail 	if (!isv6 &&
9006e91bba0SGirish Moodalbail 	    (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
9016e91bba0SGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
9026e91bba0SGirish Moodalbail 		goto delete;
9036e91bba0SGirish Moodalbail 	}
9046e91bba0SGirish Moodalbail 
9056e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
9066e91bba0SGirish Moodalbail 		/*
9076e91bba0SGirish Moodalbail 		 * This must be an address property. Delete this
9086e91bba0SGirish Moodalbail 		 * line if there is a match in the address family.
9096e91bba0SGirish Moodalbail 		 */
9106e91bba0SGirish Moodalbail 		head = aobjmap.aobjmap_head;
9116e91bba0SGirish Moodalbail 		while (head != NULL) {
9126e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname, aobjname) == 0) {
9136e91bba0SGirish Moodalbail 				aobjfound = B_TRUE;
9146e91bba0SGirish Moodalbail 				if (head->am_family == cbarg->cb_family)
9156e91bba0SGirish Moodalbail 					goto delete;
9166e91bba0SGirish Moodalbail 			}
9176e91bba0SGirish Moodalbail 			head = head->am_next;
9186e91bba0SGirish Moodalbail 		}
9196e91bba0SGirish Moodalbail 		/*
9206e91bba0SGirish Moodalbail 		 * If aobjfound = B_FALSE, then this address is not
9216e91bba0SGirish Moodalbail 		 * available in active configuration. We should go ahead
9226e91bba0SGirish Moodalbail 		 * and delete it.
9236e91bba0SGirish Moodalbail 		 */
9246e91bba0SGirish Moodalbail 		if (!aobjfound)
9256e91bba0SGirish Moodalbail 			goto delete;
9266e91bba0SGirish Moodalbail 	}
9276e91bba0SGirish Moodalbail 
9286e91bba0SGirish Moodalbail 	/*
9296e91bba0SGirish Moodalbail 	 * If we are removing both v4 and v6 interface, then we get rid of
9306e91bba0SGirish Moodalbail 	 * all the properties for that interface. On the other hand, if we
9316e91bba0SGirish Moodalbail 	 * are deleting only v4 instance of an interface, then we delete v4
9326e91bba0SGirish Moodalbail 	 * properties only.
9336e91bba0SGirish Moodalbail 	 */
9346e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
9356e91bba0SGirish Moodalbail 		proto = ipadm_str2proto(modstr);
9366e91bba0SGirish Moodalbail 		switch (proto) {
9376e91bba0SGirish Moodalbail 		case MOD_PROTO_IPV6:
9386e91bba0SGirish Moodalbail 			if (isv6)
9396e91bba0SGirish Moodalbail 				goto delete;
9406e91bba0SGirish Moodalbail 			break;
9416e91bba0SGirish Moodalbail 		case MOD_PROTO_IPV4:
9426e91bba0SGirish Moodalbail 			if (!isv6)
9436e91bba0SGirish Moodalbail 				goto delete;
9446e91bba0SGirish Moodalbail 			break;
9456e91bba0SGirish Moodalbail 		case MOD_PROTO_IP:
946a73be61aSHans Rosenfeld 			if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
947a73be61aSHans Rosenfeld 				goto delete;
9486e91bba0SGirish Moodalbail 			break;
9496e91bba0SGirish Moodalbail 		}
9506e91bba0SGirish Moodalbail 	}
9516e91bba0SGirish Moodalbail 	/* Not found a match yet. Continue processing the db */
9526e91bba0SGirish Moodalbail 	return (B_TRUE);
9536e91bba0SGirish Moodalbail delete:
9546e91bba0SGirish Moodalbail 	/* delete the line from the db */
9556e91bba0SGirish Moodalbail 	buf[0] = '\0';
9566e91bba0SGirish Moodalbail 	return (B_TRUE);
9576e91bba0SGirish Moodalbail }
9586e91bba0SGirish Moodalbail 
9596e91bba0SGirish Moodalbail /*
9606e91bba0SGirish Moodalbail  * Deletes those entries from the database for which address object name
9616e91bba0SGirish Moodalbail  * matches with the given `cbarg->cb_aobjname'
9626e91bba0SGirish Moodalbail  */
9636e91bba0SGirish Moodalbail /* ARGSUSED */
9646e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_resetaddr(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)9656e91bba0SGirish Moodalbail ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
9666e91bba0SGirish Moodalbail     int *errp)
9676e91bba0SGirish Moodalbail {
9686e91bba0SGirish Moodalbail 	ipmgmt_resetaddr_cbarg_t *cbarg = arg;
9696e91bba0SGirish Moodalbail 	char		*aobjname = cbarg->cb_aobjname;
9706e91bba0SGirish Moodalbail 
9716e91bba0SGirish Moodalbail 	*errp = 0;
9726e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_contains(db_nvl, NULL, NULL, aobjname))
9736e91bba0SGirish Moodalbail 		return (B_TRUE);
9746e91bba0SGirish Moodalbail 
9756e91bba0SGirish Moodalbail 	/* delete the line from the db */
9766e91bba0SGirish Moodalbail 	buf[0] = '\0';
9776e91bba0SGirish Moodalbail 	return (B_TRUE);
9786e91bba0SGirish Moodalbail }
9796e91bba0SGirish Moodalbail 
9806e91bba0SGirish Moodalbail /*
9816e91bba0SGirish Moodalbail  * Retrieves all interface props, including addresses, for given interface(s).
9826e91bba0SGirish Moodalbail  * `invl' contains the list of interfaces, for which information need to be
9836e91bba0SGirish Moodalbail  * retrieved.
9846e91bba0SGirish Moodalbail  */
9856e91bba0SGirish Moodalbail /* ARGSUSED */
9866e91bba0SGirish Moodalbail boolean_t
ipmgmt_db_initif(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)9876e91bba0SGirish Moodalbail ipmgmt_db_initif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
9886e91bba0SGirish Moodalbail     int *errp)
9896e91bba0SGirish Moodalbail {
9906e91bba0SGirish Moodalbail 	ipmgmt_initif_cbarg_t	*cbarg = arg;
9916e91bba0SGirish Moodalbail 	nvlist_t		*onvl = cbarg->cb_onvl;
9926e91bba0SGirish Moodalbail 	nvlist_t		*invl = cbarg->cb_invl;
9936e91bba0SGirish Moodalbail 	sa_family_t		in_af = cbarg->cb_family;
9946e91bba0SGirish Moodalbail 	char			*db_ifname;
9956e91bba0SGirish Moodalbail 
9966e91bba0SGirish Moodalbail 	*errp = 0;
9976e91bba0SGirish Moodalbail 	if (nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
9986e91bba0SGirish Moodalbail 	    nvlist_exists(invl, db_ifname)) {
9996e91bba0SGirish Moodalbail 		char		name[IPMGMT_STRSIZE];
10006e91bba0SGirish Moodalbail 		sa_family_t	db_af = in_af;
10016e91bba0SGirish Moodalbail 		uint_t		proto;
10026e91bba0SGirish Moodalbail 		char		*pstr;
10036e91bba0SGirish Moodalbail 
10046e91bba0SGirish Moodalbail 		if (in_af != AF_UNSPEC) {
10056e91bba0SGirish Moodalbail 			if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME,
10066e91bba0SGirish Moodalbail 			    &pstr) == 0) {
10076e91bba0SGirish Moodalbail 				proto = ipadm_str2proto(pstr);
10086e91bba0SGirish Moodalbail 				if (proto == MOD_PROTO_IPV4)
10096e91bba0SGirish Moodalbail 					db_af = AF_INET;
10106e91bba0SGirish Moodalbail 				else if (proto == MOD_PROTO_IPV6)
10116e91bba0SGirish Moodalbail 					db_af = AF_INET6;
10126e91bba0SGirish Moodalbail 				else
10136e91bba0SGirish Moodalbail 					db_af = in_af;
10146e91bba0SGirish Moodalbail 			} else {
10156e91bba0SGirish Moodalbail 				if (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
10166e91bba0SGirish Moodalbail 				    nvlist_exists(db_nvl, IPADM_NVP_DHCP))
10176e91bba0SGirish Moodalbail 					db_af = AF_INET;
10186e91bba0SGirish Moodalbail 				else
10196e91bba0SGirish Moodalbail 					db_af = AF_INET6;
10206e91bba0SGirish Moodalbail 			}
10216e91bba0SGirish Moodalbail 		}
10226e91bba0SGirish Moodalbail 		if (in_af == db_af) {
10236e91bba0SGirish Moodalbail 			(void) snprintf(name, sizeof (name), "%s_%d", db_ifname,
10246e91bba0SGirish Moodalbail 			    cbarg->cb_ocnt);
10256e91bba0SGirish Moodalbail 			*errp = nvlist_add_nvlist(onvl, name, db_nvl);
10266e91bba0SGirish Moodalbail 			if (*errp == 0)
10276e91bba0SGirish Moodalbail 				cbarg->cb_ocnt++;
10286e91bba0SGirish Moodalbail 		}
10296e91bba0SGirish Moodalbail 	}
10306e91bba0SGirish Moodalbail 	return (B_TRUE);
10316e91bba0SGirish Moodalbail }
10326e91bba0SGirish Moodalbail 
10336e91bba0SGirish Moodalbail /*
10346e91bba0SGirish Moodalbail  * helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
10356e91bba0SGirish Moodalbail  * into `aobjmap' structure.
10366e91bba0SGirish Moodalbail  */
10376e91bba0SGirish Moodalbail static int
i_ipmgmt_add_amnode(ipmgmt_aobjmap_t * nodep)10386e91bba0SGirish Moodalbail i_ipmgmt_add_amnode(ipmgmt_aobjmap_t *nodep)
10396e91bba0SGirish Moodalbail {
10406e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*new, *head;
10416e91bba0SGirish Moodalbail 
10426e91bba0SGirish Moodalbail 	head = aobjmap.aobjmap_head;
10436e91bba0SGirish Moodalbail 	if ((new = malloc(sizeof (ipmgmt_aobjmap_t))) == NULL)
10446e91bba0SGirish Moodalbail 		return (ENOMEM);
10456e91bba0SGirish Moodalbail 	*new = *nodep;
10466e91bba0SGirish Moodalbail 	new->am_next = NULL;
10476e91bba0SGirish Moodalbail 
10486e91bba0SGirish Moodalbail 	/* Add the node at the beginning of the list */
10496e91bba0SGirish Moodalbail 	if (head == NULL) {
10506e91bba0SGirish Moodalbail 		aobjmap.aobjmap_head = new;
10516e91bba0SGirish Moodalbail 	} else {
10526e91bba0SGirish Moodalbail 		new->am_next = aobjmap.aobjmap_head;
10536e91bba0SGirish Moodalbail 		aobjmap.aobjmap_head = new;
10546e91bba0SGirish Moodalbail 	}
10556e91bba0SGirish Moodalbail 	return (0);
10566e91bba0SGirish Moodalbail }
10576e91bba0SGirish Moodalbail 
10586e91bba0SGirish Moodalbail /*
10596e91bba0SGirish Moodalbail  * A recursive function to generate alphabetized number given a decimal number.
10606e91bba0SGirish Moodalbail  * Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
10616e91bba0SGirish Moodalbail  * 'ab', 'ac', et al.
10626e91bba0SGirish Moodalbail  */
10636e91bba0SGirish Moodalbail static void
i_ipmgmt_num2priv_aobjname(uint32_t num,char ** cp,char * endp)10646e91bba0SGirish Moodalbail i_ipmgmt_num2priv_aobjname(uint32_t num, char **cp, char *endp)
10656e91bba0SGirish Moodalbail {
10666e91bba0SGirish Moodalbail 	if (num >= 26)
10676e91bba0SGirish Moodalbail 		i_ipmgmt_num2priv_aobjname(num / 26 - 1, cp, endp);
10686e91bba0SGirish Moodalbail 	if (*cp != endp) {
10696e91bba0SGirish Moodalbail 		*cp[0] = 'a' + (num % 26);
10706e91bba0SGirish Moodalbail 		(*cp)++;
10716e91bba0SGirish Moodalbail 	}
10726e91bba0SGirish Moodalbail }
10736e91bba0SGirish Moodalbail 
10746e91bba0SGirish Moodalbail /*
10756e91bba0SGirish Moodalbail  * This function generates an `aobjname', when required, and then does
10766e91bba0SGirish Moodalbail  * lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
10776e91bba0SGirish Moodalbail  * through the `aobjmap' to check if an address object with the same
10786e91bba0SGirish Moodalbail  * `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
10796e91bba0SGirish Moodalbail  * `aobjname's are not allowed.
10806e91bba0SGirish Moodalbail  *
10816e91bba0SGirish Moodalbail  * If `nodep->am_aobjname' is an empty string then the daemon generates an
10826e91bba0SGirish Moodalbail  * `aobjname' using the `am_nextnum', which contains the next number to be
10836e91bba0SGirish Moodalbail  * used to generate `aobjname'. `am_nextnum' is converted to base26 using
10846e91bba0SGirish Moodalbail  * `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
10856e91bba0SGirish Moodalbail  *
10866e91bba0SGirish Moodalbail  * `am_nextnum' will be 0 to begin with. Every time an address object that
10876e91bba0SGirish Moodalbail  * needs `aobjname' is added it's incremented by 1. So for the first address
10886e91bba0SGirish Moodalbail  * object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
10896e91bba0SGirish Moodalbail  * For the second address object on that interface `am_aobjname' will be net0/_b
10906e91bba0SGirish Moodalbail  * and  `am_nextnum' will incremented to 2.
10916e91bba0SGirish Moodalbail  */
10926e91bba0SGirish Moodalbail static int
i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t * nodep)10936e91bba0SGirish Moodalbail i_ipmgmt_lookupadd_amnode(ipmgmt_aobjmap_t *nodep)
10946e91bba0SGirish Moodalbail {
10956e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*head;
10966e91bba0SGirish Moodalbail 	uint32_t		nextnum;
10976e91bba0SGirish Moodalbail 
10986e91bba0SGirish Moodalbail 	for (head = aobjmap.aobjmap_head; head != NULL; head = head->am_next)
10996e91bba0SGirish Moodalbail 		if (strcmp(head->am_ifname, nodep->am_ifname) == 0)
11006e91bba0SGirish Moodalbail 			break;
11016e91bba0SGirish Moodalbail 	nextnum = (head == NULL ? 0 : head->am_nextnum);
11026e91bba0SGirish Moodalbail 
11036e91bba0SGirish Moodalbail 	/*
11046e91bba0SGirish Moodalbail 	 * if `aobjname' is empty, then the daemon has to generate the
11056e91bba0SGirish Moodalbail 	 * next `aobjname' for the given interface and family.
11066e91bba0SGirish Moodalbail 	 */
11076e91bba0SGirish Moodalbail 	if (nodep->am_aobjname[0] == '\0') {
11086e91bba0SGirish Moodalbail 		char tmpstr[IPADM_AOBJ_USTRSIZ - 1];  /* 1 for leading  '_' */
11096e91bba0SGirish Moodalbail 		char *cp = tmpstr;
11106e91bba0SGirish Moodalbail 		char *endp = tmpstr + sizeof (tmpstr);
11116e91bba0SGirish Moodalbail 
11126e91bba0SGirish Moodalbail 		i_ipmgmt_num2priv_aobjname(nextnum, &cp, endp);
11136e91bba0SGirish Moodalbail 
11146e91bba0SGirish Moodalbail 		if (cp == endp)
11156e91bba0SGirish Moodalbail 			return (EINVAL);
11166e91bba0SGirish Moodalbail 		cp[0] = '\0';
11176e91bba0SGirish Moodalbail 
11186e91bba0SGirish Moodalbail 		if (snprintf(nodep->am_aobjname, IPADM_AOBJSIZ, "%s/_%s",
11196e91bba0SGirish Moodalbail 		    nodep->am_ifname, tmpstr) >= IPADM_AOBJSIZ) {
11206e91bba0SGirish Moodalbail 			return (EINVAL);
11216e91bba0SGirish Moodalbail 		}
11226e91bba0SGirish Moodalbail 		nodep->am_nextnum = ++nextnum;
11236e91bba0SGirish Moodalbail 	} else {
11246e91bba0SGirish Moodalbail 		for (head = aobjmap.aobjmap_head; head != NULL;
11256e91bba0SGirish Moodalbail 		    head = head->am_next) {
11266e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname, nodep->am_aobjname) == 0)
11276e91bba0SGirish Moodalbail 				return (EEXIST);
11286e91bba0SGirish Moodalbail 		}
11296e91bba0SGirish Moodalbail 		nodep->am_nextnum = nextnum;
11306e91bba0SGirish Moodalbail 	}
11316e91bba0SGirish Moodalbail 	return (i_ipmgmt_add_amnode(nodep));
11326e91bba0SGirish Moodalbail }
11336e91bba0SGirish Moodalbail 
11346e91bba0SGirish Moodalbail /*
11356e91bba0SGirish Moodalbail  * Performs following operations on the global `aobjmap' linked list.
11366e91bba0SGirish Moodalbail  * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
11376e91bba0SGirish Moodalbail  * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
11386e91bba0SGirish Moodalbail  * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
1139ec3706caSVasumathi Sundaram  * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
11406e91bba0SGirish Moodalbail  */
11416e91bba0SGirish Moodalbail int
ipmgmt_aobjmap_op(ipmgmt_aobjmap_t * nodep,uint32_t op)11426e91bba0SGirish Moodalbail ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
11436e91bba0SGirish Moodalbail {
1144ec3706caSVasumathi Sundaram 	ipmgmt_aobjmap_t	*head, *prev, *matched = NULL;
11456e91bba0SGirish Moodalbail 	boolean_t		update = B_TRUE;
11466e91bba0SGirish Moodalbail 	int			err = 0;
1147a73be61aSHans Rosenfeld 	ipadm_db_op_t		db_op = IPADM_DB_READ;
11486e91bba0SGirish Moodalbail 
11496e91bba0SGirish Moodalbail 	(void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
11506e91bba0SGirish Moodalbail 
11516e91bba0SGirish Moodalbail 	head = aobjmap.aobjmap_head;
11526e91bba0SGirish Moodalbail 	switch (op) {
11536e91bba0SGirish Moodalbail 	case ADDROBJ_ADD:
11546e91bba0SGirish Moodalbail 		/*
11556e91bba0SGirish Moodalbail 		 * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
11566e91bba0SGirish Moodalbail 		 * update, else add the new node.
11576e91bba0SGirish Moodalbail 		 */
11586e91bba0SGirish Moodalbail 		for (; head != NULL; head = head->am_next) {
1159ec3706caSVasumathi Sundaram 			/*
1160ec3706caSVasumathi Sundaram 			 * For IPv6, we need to distinguish between the
1161ec3706caSVasumathi Sundaram 			 * linklocal and non-linklocal nodes
1162ec3706caSVasumathi Sundaram 			 */
11636e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname,
1164ec3706caSVasumathi Sundaram 			    nodep->am_aobjname) == 0 &&
1165ec3706caSVasumathi Sundaram 			    (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
1166b31320a7SChris Fraire 			    head->ipmgmt_am_linklocal ==
1167b31320a7SChris Fraire 			    nodep->ipmgmt_am_linklocal))
11686e91bba0SGirish Moodalbail 				break;
11696e91bba0SGirish Moodalbail 		}
11706e91bba0SGirish Moodalbail 
11716e91bba0SGirish Moodalbail 		if (head != NULL) {
11726e91bba0SGirish Moodalbail 			/* update the node */
11736e91bba0SGirish Moodalbail 			(void) strlcpy(head->am_ifname, nodep->am_ifname,
11746e91bba0SGirish Moodalbail 			    sizeof (head->am_ifname));
11756e91bba0SGirish Moodalbail 			head->am_lnum = nodep->am_lnum;
11766e91bba0SGirish Moodalbail 			head->am_family = nodep->am_family;
11776e91bba0SGirish Moodalbail 			head->am_flags = nodep->am_flags;
11786e91bba0SGirish Moodalbail 			head->am_atype = nodep->am_atype;
1179b31320a7SChris Fraire 			head->am_atype_cache = nodep->am_atype_cache;
11806e91bba0SGirish Moodalbail 		} else {
11816e91bba0SGirish Moodalbail 			for (head = aobjmap.aobjmap_head; head != NULL;
11826e91bba0SGirish Moodalbail 			    head = head->am_next) {
11836e91bba0SGirish Moodalbail 				if (strcmp(head->am_ifname,
11846e91bba0SGirish Moodalbail 				    nodep->am_ifname) == 0)
11856e91bba0SGirish Moodalbail 					break;
11866e91bba0SGirish Moodalbail 			}
11876e91bba0SGirish Moodalbail 			nodep->am_nextnum = (head == NULL ? 0 :
11886e91bba0SGirish Moodalbail 			    head->am_nextnum);
11896e91bba0SGirish Moodalbail 			err = i_ipmgmt_add_amnode(nodep);
11906e91bba0SGirish Moodalbail 		}
11916e91bba0SGirish Moodalbail 		db_op = IPADM_DB_WRITE;
11926e91bba0SGirish Moodalbail 		break;
11936e91bba0SGirish Moodalbail 	case ADDROBJ_DELETE:
11946e91bba0SGirish Moodalbail 		prev = head;
11956e91bba0SGirish Moodalbail 		while (head != NULL) {
11966e91bba0SGirish Moodalbail 			if (strcmp(head->am_aobjname,
11976e91bba0SGirish Moodalbail 			    nodep->am_aobjname) == 0) {
11986e91bba0SGirish Moodalbail 				nodep->am_atype = head->am_atype;
11996e91bba0SGirish Moodalbail 				/*
12006e91bba0SGirish Moodalbail 				 * There could be multiple IPV6_ADDRCONF nodes,
12016e91bba0SGirish Moodalbail 				 * with same address object name, so check for
12026e91bba0SGirish Moodalbail 				 * logical number also.
12036e91bba0SGirish Moodalbail 				 */
12046e91bba0SGirish Moodalbail 				if (head->am_atype !=
12056e91bba0SGirish Moodalbail 				    IPADM_ADDR_IPV6_ADDRCONF ||
12066e91bba0SGirish Moodalbail 				    nodep->am_lnum == head->am_lnum)
12076e91bba0SGirish Moodalbail 					break;
12086e91bba0SGirish Moodalbail 			}
12096e91bba0SGirish Moodalbail 			prev = head;
12106e91bba0SGirish Moodalbail 			head = head->am_next;
12116e91bba0SGirish Moodalbail 		}
12126e91bba0SGirish Moodalbail 		if (head != NULL) {
12136e91bba0SGirish Moodalbail 			/*
12146e91bba0SGirish Moodalbail 			 * If the address object is in both active and
12156e91bba0SGirish Moodalbail 			 * persistent configuration and the user is deleting it
12166e91bba0SGirish Moodalbail 			 * only from active configuration then mark this node
12176e91bba0SGirish Moodalbail 			 * for deletion by reseting IPMGMT_ACTIVE bit.
12186e91bba0SGirish Moodalbail 			 * With this the same address object name cannot
12196e91bba0SGirish Moodalbail 			 * be reused until it is permanently removed.
12206e91bba0SGirish Moodalbail 			 */
12216e91bba0SGirish Moodalbail 			if (head->am_flags == (IPMGMT_ACTIVE|IPMGMT_PERSIST) &&
12226e91bba0SGirish Moodalbail 			    nodep->am_flags == IPMGMT_ACTIVE) {
12236e91bba0SGirish Moodalbail 				/* Update flags in the in-memory map. */
12246e91bba0SGirish Moodalbail 				head->am_flags &= ~IPMGMT_ACTIVE;
12256e91bba0SGirish Moodalbail 				head->am_lnum = -1;
12266e91bba0SGirish Moodalbail 
12276e91bba0SGirish Moodalbail 				/* Update info in file. */
12286e91bba0SGirish Moodalbail 				db_op = IPADM_DB_WRITE;
12296e91bba0SGirish Moodalbail 				*nodep = *head;
12306e91bba0SGirish Moodalbail 			} else {
12316e91bba0SGirish Moodalbail 				(void) strlcpy(nodep->am_ifname,
12326e91bba0SGirish Moodalbail 				    head->am_ifname,
12336e91bba0SGirish Moodalbail 				    sizeof (nodep->am_ifname));
12346e91bba0SGirish Moodalbail 				/* otherwise delete the node */
12356e91bba0SGirish Moodalbail 				if (head == aobjmap.aobjmap_head)
12366e91bba0SGirish Moodalbail 					aobjmap.aobjmap_head = head->am_next;
12376e91bba0SGirish Moodalbail 				else
12386e91bba0SGirish Moodalbail 					prev->am_next = head->am_next;
12396e91bba0SGirish Moodalbail 				free(head);
12406e91bba0SGirish Moodalbail 				db_op = IPADM_DB_DELETE;
12416e91bba0SGirish Moodalbail 			}
12426e91bba0SGirish Moodalbail 		} else {
12436e91bba0SGirish Moodalbail 			err = ENOENT;
12446e91bba0SGirish Moodalbail 		}
12456e91bba0SGirish Moodalbail 		break;
12466e91bba0SGirish Moodalbail 	case ADDROBJ_LOOKUPADD:
12476e91bba0SGirish Moodalbail 		err = i_ipmgmt_lookupadd_amnode(nodep);
12486e91bba0SGirish Moodalbail 		update = B_FALSE;
12496e91bba0SGirish Moodalbail 		break;
1250ec3706caSVasumathi Sundaram 	case ADDROBJ_SETLIFNUM:
1251ec3706caSVasumathi Sundaram 		update = B_FALSE;
1252ec3706caSVasumathi Sundaram 		for (; head != NULL; head = head->am_next) {
1253ec3706caSVasumathi Sundaram 			if (strcmp(head->am_ifname,
1254ec3706caSVasumathi Sundaram 			    nodep->am_ifname) == 0 &&
1255ec3706caSVasumathi Sundaram 			    head->am_family == nodep->am_family &&
1256ec3706caSVasumathi Sundaram 			    head->am_lnum == nodep->am_lnum) {
1257ec3706caSVasumathi Sundaram 				err = EEXIST;
1258ec3706caSVasumathi Sundaram 				break;
1259ec3706caSVasumathi Sundaram 			}
1260ec3706caSVasumathi Sundaram 			if (strcmp(head->am_aobjname,
1261ec3706caSVasumathi Sundaram 			    nodep->am_aobjname) == 0) {
1262ec3706caSVasumathi Sundaram 				matched = head;
1263ec3706caSVasumathi Sundaram 			}
1264ec3706caSVasumathi Sundaram 		}
1265ec3706caSVasumathi Sundaram 		if (err == EEXIST)
1266ec3706caSVasumathi Sundaram 			break;
1267ec3706caSVasumathi Sundaram 		if (matched != NULL) {
1268ec3706caSVasumathi Sundaram 			/* update the lifnum */
1269ec3706caSVasumathi Sundaram 			matched->am_lnum = nodep->am_lnum;
1270ec3706caSVasumathi Sundaram 		} else {
1271ec3706caSVasumathi Sundaram 			err = ENOENT;
1272ec3706caSVasumathi Sundaram 		}
1273ec3706caSVasumathi Sundaram 		break;
12746e91bba0SGirish Moodalbail 	default:
12756e91bba0SGirish Moodalbail 		assert(0);
12766e91bba0SGirish Moodalbail 	}
12776e91bba0SGirish Moodalbail 
12786e91bba0SGirish Moodalbail 	if (err == 0 && update)
12796e91bba0SGirish Moodalbail 		err = ipmgmt_persist_aobjmap(nodep, db_op);
12806e91bba0SGirish Moodalbail 
12816e91bba0SGirish Moodalbail 	(void) pthread_rwlock_unlock(&aobjmap.aobjmap_rwlock);
12826e91bba0SGirish Moodalbail 
12836e91bba0SGirish Moodalbail 	return (err);
12846e91bba0SGirish Moodalbail }
12856e91bba0SGirish Moodalbail 
12866e91bba0SGirish Moodalbail /*
12876e91bba0SGirish Moodalbail  * Given a node in `aobjmap', this function converts it into nvlist_t structure.
12886e91bba0SGirish Moodalbail  * The content to be written to DB must be represented as nvlist_t.
12896e91bba0SGirish Moodalbail  */
12906e91bba0SGirish Moodalbail static int
i_ipmgmt_node2nvl(nvlist_t ** nvl,ipmgmt_aobjmap_t * np)12916e91bba0SGirish Moodalbail i_ipmgmt_node2nvl(nvlist_t **nvl, ipmgmt_aobjmap_t *np)
12926e91bba0SGirish Moodalbail {
12936e91bba0SGirish Moodalbail 	int	err;
12946e91bba0SGirish Moodalbail 	char	strval[IPMGMT_STRSIZE];
12956e91bba0SGirish Moodalbail 
12966e91bba0SGirish Moodalbail 	*nvl = NULL;
12976e91bba0SGirish Moodalbail 	if ((err = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0)) != 0)
12986e91bba0SGirish Moodalbail 		goto fail;
12996e91bba0SGirish Moodalbail 
13006e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_AOBJNAME,
13016e91bba0SGirish Moodalbail 	    np->am_aobjname)) != 0)
13026e91bba0SGirish Moodalbail 		goto fail;
13036e91bba0SGirish Moodalbail 
13046e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_IFNAME,
13056e91bba0SGirish Moodalbail 	    np->am_ifname)) != 0)
13066e91bba0SGirish Moodalbail 		goto fail;
13076e91bba0SGirish Moodalbail 
13086e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_lnum);
13096e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_LIFNUM, strval)) != 0)
13106e91bba0SGirish Moodalbail 		goto fail;
13116e91bba0SGirish Moodalbail 
13126e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_family);
13136e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, IPADM_NVP_FAMILY, strval)) != 0)
13146e91bba0SGirish Moodalbail 		goto fail;
13156e91bba0SGirish Moodalbail 
13166e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_flags);
13176e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, FLAGS, strval)) != 0)
13186e91bba0SGirish Moodalbail 		goto fail;
13196e91bba0SGirish Moodalbail 
13206e91bba0SGirish Moodalbail 	(void) snprintf(strval, IPMGMT_STRSIZE, "%d", np->am_atype);
13216e91bba0SGirish Moodalbail 	if ((err = nvlist_add_string(*nvl, ATYPE, strval)) != 0)
13226e91bba0SGirish Moodalbail 		goto fail;
13236e91bba0SGirish Moodalbail 
1324b31320a7SChris Fraire 	switch (np->am_atype) {
1325b31320a7SChris Fraire 		case IPADM_ADDR_IPV6_ADDRCONF: {
1326b31320a7SChris Fraire 			struct sockaddr_in6	*in6;
13276e91bba0SGirish Moodalbail 
1328b31320a7SChris Fraire 			in6 = &np->ipmgmt_am_ifid;
1329b31320a7SChris Fraire 			if (np->ipmgmt_am_linklocal &&
1330b31320a7SChris Fraire 			    IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
1331b31320a7SChris Fraire 				if ((err = nvlist_add_string(*nvl,
1332b31320a7SChris Fraire 				    IPADM_NVP_IPNUMADDR, "default")) != 0) {
1333b31320a7SChris Fraire 					goto fail;
1334b31320a7SChris Fraire 				}
1335b31320a7SChris Fraire 			} else {
1336b31320a7SChris Fraire 				if (inet_ntop(AF_INET6, &in6->sin6_addr, strval,
1337b31320a7SChris Fraire 				    IPMGMT_STRSIZE) == NULL) {
1338b31320a7SChris Fraire 					err = errno;
1339b31320a7SChris Fraire 					goto fail;
1340b31320a7SChris Fraire 				}
1341b31320a7SChris Fraire 				if ((err = nvlist_add_string(*nvl,
1342b31320a7SChris Fraire 				    IPADM_NVP_IPNUMADDR, strval)) != 0) {
1343b31320a7SChris Fraire 					goto fail;
1344b31320a7SChris Fraire 				}
13456e91bba0SGirish Moodalbail 			}
1346b31320a7SChris Fraire 		}
1347b31320a7SChris Fraire 			break;
1348b31320a7SChris Fraire 		case IPADM_ADDR_DHCP: {
1349*924ac941SToomas Soome 			if (*np->ipmgmt_am_reqhost != '\0' &&
1350b31320a7SChris Fraire 			    (err = nvlist_add_string(*nvl, IPADM_NVP_REQHOST,
1351b31320a7SChris Fraire 			    np->ipmgmt_am_reqhost)) != 0)
13526e91bba0SGirish Moodalbail 				goto fail;
13536e91bba0SGirish Moodalbail 		}
1354b31320a7SChris Fraire 			/* FALLTHRU */
1355b31320a7SChris Fraire 		default:
1356b31320a7SChris Fraire 			if ((err = nvlist_add_string(*nvl, IPADM_NVP_IPNUMADDR,
1357b31320a7SChris Fraire 			    "")) != 0)
1358b31320a7SChris Fraire 				goto fail;
1359b31320a7SChris Fraire 			break;
13606e91bba0SGirish Moodalbail 	}
13616e91bba0SGirish Moodalbail 	return (err);
13626e91bba0SGirish Moodalbail fail:
13636e91bba0SGirish Moodalbail 	nvlist_free(*nvl);
13646e91bba0SGirish Moodalbail 	return (err);
13656e91bba0SGirish Moodalbail }
13666e91bba0SGirish Moodalbail 
13676e91bba0SGirish Moodalbail /*
13686e91bba0SGirish Moodalbail  * Read the aobjmap data store and build the in-memory representation
13696e91bba0SGirish Moodalbail  * of the aobjmap. We don't need to hold any locks while building this as
13706e91bba0SGirish Moodalbail  * we do this in very early stage of daemon coming up, even before the door
13716e91bba0SGirish Moodalbail  * is opened.
13726e91bba0SGirish Moodalbail  */
13736e91bba0SGirish Moodalbail /* ARGSUSED */
13746e91bba0SGirish Moodalbail extern boolean_t
ipmgmt_aobjmap_init(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)13756e91bba0SGirish Moodalbail ipmgmt_aobjmap_init(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
13766e91bba0SGirish Moodalbail     int *errp)
13776e91bba0SGirish Moodalbail {
13786e91bba0SGirish Moodalbail 	nvpair_t		*nvp = NULL;
13796e91bba0SGirish Moodalbail 	char			*name, *strval = NULL;
1380ab618543SJohn Levon 	ipmgmt_aobjmap_t	node;
13816e91bba0SGirish Moodalbail 	struct sockaddr_in6	*in6;
13826e91bba0SGirish Moodalbail 
13836e91bba0SGirish Moodalbail 	*errp = 0;
13846e91bba0SGirish Moodalbail 	node.am_next = NULL;
13856e91bba0SGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
13866e91bba0SGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
13876e91bba0SGirish Moodalbail 		name = nvpair_name(nvp);
13886e91bba0SGirish Moodalbail 
13896e91bba0SGirish Moodalbail 		if ((*errp = nvpair_value_string(nvp, &strval)) != 0)
13906e91bba0SGirish Moodalbail 			return (B_TRUE);
13916e91bba0SGirish Moodalbail 		if (strcmp(IPADM_NVP_AOBJNAME, name) == 0) {
13926e91bba0SGirish Moodalbail 			(void) strlcpy(node.am_aobjname, strval,
13936e91bba0SGirish Moodalbail 			    sizeof (node.am_aobjname));
13946e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_IFNAME, name) == 0) {
13956e91bba0SGirish Moodalbail 			(void) strlcpy(node.am_ifname, strval,
13966e91bba0SGirish Moodalbail 			    sizeof (node.am_ifname));
13976e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_LIFNUM, name) == 0) {
13986e91bba0SGirish Moodalbail 			node.am_lnum = atoi(strval);
13996e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_FAMILY, name) == 0) {
14006e91bba0SGirish Moodalbail 			node.am_family = (sa_family_t)atoi(strval);
14016e91bba0SGirish Moodalbail 		} else if (strcmp(FLAGS, name) == 0) {
14026e91bba0SGirish Moodalbail 			node.am_flags = atoi(strval);
14036e91bba0SGirish Moodalbail 		} else if (strcmp(ATYPE, name) == 0) {
14046e91bba0SGirish Moodalbail 			node.am_atype = (ipadm_addr_type_t)atoi(strval);
14056e91bba0SGirish Moodalbail 		} else if (strcmp(IPADM_NVP_IPNUMADDR, name) == 0) {
14066e91bba0SGirish Moodalbail 			if (node.am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
1407b31320a7SChris Fraire 				in6 = &node.ipmgmt_am_ifid;
14086e91bba0SGirish Moodalbail 				if (strcmp(strval, "default") == 0) {
1409b31320a7SChris Fraire 					bzero(in6,
1410b31320a7SChris Fraire 					    sizeof (node.ipmgmt_am_ifid));
1411b31320a7SChris Fraire 					node.ipmgmt_am_linklocal = B_TRUE;
14126e91bba0SGirish Moodalbail 				} else {
14136e91bba0SGirish Moodalbail 					(void) inet_pton(AF_INET6, strval,
14146e91bba0SGirish Moodalbail 					    &in6->sin6_addr);
14156e91bba0SGirish Moodalbail 					if (IN6_IS_ADDR_UNSPECIFIED(
14166e91bba0SGirish Moodalbail 					    &in6->sin6_addr))
1417b31320a7SChris Fraire 						node.ipmgmt_am_linklocal =
1418b31320a7SChris Fraire 						    B_TRUE;
14196e91bba0SGirish Moodalbail 				}
14206e91bba0SGirish Moodalbail 			}
14216e91bba0SGirish Moodalbail 		}
14226e91bba0SGirish Moodalbail 	}
14236e91bba0SGirish Moodalbail 
14246e91bba0SGirish Moodalbail 	/* we have all the information we need, add the node */
14256e91bba0SGirish Moodalbail 	*errp = i_ipmgmt_add_amnode(&node);
14266e91bba0SGirish Moodalbail 
14276e91bba0SGirish Moodalbail 	return (B_TRUE);
14286e91bba0SGirish Moodalbail }
14296e91bba0SGirish Moodalbail 
14306e91bba0SGirish Moodalbail /*
14316e91bba0SGirish Moodalbail  * Updates an entry from the temporary cache file, which matches the given
14326e91bba0SGirish Moodalbail  * address object name.
14336e91bba0SGirish Moodalbail  */
14346e91bba0SGirish Moodalbail /* ARGSUSED */
14356e91bba0SGirish Moodalbail static boolean_t
ipmgmt_update_aobjmap(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)14366e91bba0SGirish Moodalbail ipmgmt_update_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
14376e91bba0SGirish Moodalbail     size_t buflen, int *errp)
14386e91bba0SGirish Moodalbail {
14396e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	*cb = arg;
14406e91bba0SGirish Moodalbail 	nvlist_t		*in_nvl = cb->dbw_nvl;
14416e91bba0SGirish Moodalbail 	uint32_t		flags = cb->dbw_flags;
14426e91bba0SGirish Moodalbail 	char			*db_lifnumstr = NULL, *in_lifnumstr = NULL;
14436e91bba0SGirish Moodalbail 
14446e91bba0SGirish Moodalbail 	*errp = 0;
14456e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
14466e91bba0SGirish Moodalbail 		return (B_TRUE);
14476e91bba0SGirish Moodalbail 
14486e91bba0SGirish Moodalbail 	if (flags & IPMGMT_ATYPE_V6ACONF) {
14496e91bba0SGirish Moodalbail 		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
14506e91bba0SGirish Moodalbail 		    &db_lifnumstr) != 0 ||
14516e91bba0SGirish Moodalbail 		    nvlist_lookup_string(in_nvl, IPADM_NVP_LIFNUM,
14526e91bba0SGirish Moodalbail 		    &in_lifnumstr) != 0 ||
14536e91bba0SGirish Moodalbail 		    (atoi(db_lifnumstr) != -1 && atoi(in_lifnumstr) != -1 &&
14546e91bba0SGirish Moodalbail 		    strcmp(db_lifnumstr, in_lifnumstr) != 0))
14556e91bba0SGirish Moodalbail 			return (B_TRUE);
14566e91bba0SGirish Moodalbail 	}
14576e91bba0SGirish Moodalbail 
14586e91bba0SGirish Moodalbail 	/* we found the match */
14596e91bba0SGirish Moodalbail 	(void) memset(buf, 0, buflen);
14606e91bba0SGirish Moodalbail 	if (ipadm_nvlist2str(in_nvl, buf, buflen) == 0) {
14616e91bba0SGirish Moodalbail 		/* buffer overflow */
14626e91bba0SGirish Moodalbail 		*errp = ENOBUFS;
14636e91bba0SGirish Moodalbail 	}
14646e91bba0SGirish Moodalbail 
14656e91bba0SGirish Moodalbail 	/* stop the walker */
14666e91bba0SGirish Moodalbail 	return (B_FALSE);
14676e91bba0SGirish Moodalbail }
14686e91bba0SGirish Moodalbail 
14696e91bba0SGirish Moodalbail /*
14706e91bba0SGirish Moodalbail  * Deletes an entry from the temporary cache file, which matches the given
14716e91bba0SGirish Moodalbail  * address object name.
14726e91bba0SGirish Moodalbail  */
14736e91bba0SGirish Moodalbail /* ARGSUSED */
14746e91bba0SGirish Moodalbail static boolean_t
ipmgmt_delete_aobjmap(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)14756e91bba0SGirish Moodalbail ipmgmt_delete_aobjmap(void *arg, nvlist_t *db_nvl, char *buf,
14766e91bba0SGirish Moodalbail     size_t buflen, int *errp)
14776e91bba0SGirish Moodalbail {
14786e91bba0SGirish Moodalbail 	ipmgmt_aobjmap_t	*nodep = arg;
14796e91bba0SGirish Moodalbail 	char			*db_lifnumstr = NULL;
14806e91bba0SGirish Moodalbail 
14816e91bba0SGirish Moodalbail 	*errp = 0;
14826e91bba0SGirish Moodalbail 	if (!ipmgmt_nvlist_match(db_nvl, NULL, nodep->am_ifname,
14836e91bba0SGirish Moodalbail 	    nodep->am_aobjname))
14846e91bba0SGirish Moodalbail 		return (B_TRUE);
14856e91bba0SGirish Moodalbail 
14866e91bba0SGirish Moodalbail 	if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF) {
14876e91bba0SGirish Moodalbail 		if (nvlist_lookup_string(db_nvl, IPADM_NVP_LIFNUM,
14886e91bba0SGirish Moodalbail 		    &db_lifnumstr) != 0 || atoi(db_lifnumstr) != nodep->am_lnum)
14896e91bba0SGirish Moodalbail 			return (B_TRUE);
14906e91bba0SGirish Moodalbail 	}
14916e91bba0SGirish Moodalbail 
14926e91bba0SGirish Moodalbail 	/* we found the match, delete the line from the db */
14936e91bba0SGirish Moodalbail 	buf[0] = '\0';
14946e91bba0SGirish Moodalbail 
14956e91bba0SGirish Moodalbail 	/* stop the walker */
14966e91bba0SGirish Moodalbail 	return (B_FALSE);
14976e91bba0SGirish Moodalbail }
14986e91bba0SGirish Moodalbail 
14996e91bba0SGirish Moodalbail /*
15006e91bba0SGirish Moodalbail  * Adds or deletes aobjmap node information into a temporary cache file.
15016e91bba0SGirish Moodalbail  */
15026e91bba0SGirish Moodalbail extern int
ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t * nodep,ipadm_db_op_t op)15036e91bba0SGirish Moodalbail ipmgmt_persist_aobjmap(ipmgmt_aobjmap_t *nodep, ipadm_db_op_t op)
15046e91bba0SGirish Moodalbail {
15056e91bba0SGirish Moodalbail 	int			err;
15066e91bba0SGirish Moodalbail 	ipadm_dbwrite_cbarg_t	cb;
15076e91bba0SGirish Moodalbail 	nvlist_t		*nvl = NULL;
15086e91bba0SGirish Moodalbail 
15096e91bba0SGirish Moodalbail 	if (op == IPADM_DB_WRITE) {
15106e91bba0SGirish Moodalbail 		if ((err = i_ipmgmt_node2nvl(&nvl, nodep)) != 0)
15116e91bba0SGirish Moodalbail 			return (err);
15126e91bba0SGirish Moodalbail 		cb.dbw_nvl = nvl;
15136e91bba0SGirish Moodalbail 		if (nodep->am_atype == IPADM_ADDR_IPV6_ADDRCONF)
15146e91bba0SGirish Moodalbail 			cb.dbw_flags = IPMGMT_ATYPE_V6ACONF;
15156e91bba0SGirish Moodalbail 		else
15166e91bba0SGirish Moodalbail 			cb.dbw_flags = 0;
15176e91bba0SGirish Moodalbail 
15186e91bba0SGirish Moodalbail 		err = ipadm_rw_db(ipmgmt_update_aobjmap, &cb,
15196e91bba0SGirish Moodalbail 		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_WRITE);
15206e91bba0SGirish Moodalbail 		nvlist_free(nvl);
15216e91bba0SGirish Moodalbail 	} else {
15226e91bba0SGirish Moodalbail 		assert(op == IPADM_DB_DELETE);
15236e91bba0SGirish Moodalbail 
15246e91bba0SGirish Moodalbail 		err = ipadm_rw_db(ipmgmt_delete_aobjmap, nodep,
15256e91bba0SGirish Moodalbail 		    ADDROBJ_MAPPING_DB_FILE, IPADM_FILE_MODE, IPADM_DB_DELETE);
15266e91bba0SGirish Moodalbail 	}
15276e91bba0SGirish Moodalbail 	return (err);
15286e91bba0SGirish Moodalbail }
1529550b6e40SSowmini Varadhan 
15308887b57dSGirish Moodalbail /*
15318887b57dSGirish Moodalbail  * upgrades the ipadm data-store. It renames all the old private protocol
15328887b57dSGirish Moodalbail  * property names which start with leading protocol names to begin with
15338887b57dSGirish Moodalbail  * IPADM_PRIV_PROP_PREFIX.
15348887b57dSGirish Moodalbail  */
15358887b57dSGirish Moodalbail /* ARGSUSED */
15368887b57dSGirish Moodalbail boolean_t
ipmgmt_db_upgrade(void * arg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)15378887b57dSGirish Moodalbail ipmgmt_db_upgrade(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
15388887b57dSGirish Moodalbail     int *errp)
15398887b57dSGirish Moodalbail {
15408887b57dSGirish Moodalbail 	nvpair_t	*nvp;
15418887b57dSGirish Moodalbail 	char		*name, *pname = NULL, *protostr = NULL, *pval = NULL;
15428887b57dSGirish Moodalbail 	uint_t		proto, nproto;
15438887b57dSGirish Moodalbail 	char		nname[IPMGMT_STRSIZE], tmpstr[IPMGMT_STRSIZE];
15448887b57dSGirish Moodalbail 
15458887b57dSGirish Moodalbail 	*errp = 0;
15468887b57dSGirish Moodalbail 	/*
15478887b57dSGirish Moodalbail 	 * We are interested in lines which contain protocol properties. We
15488887b57dSGirish Moodalbail 	 * walk through other lines in the DB.
15498887b57dSGirish Moodalbail 	 */
15508887b57dSGirish Moodalbail 	if (nvlist_exists(db_nvl, IPADM_NVP_IFNAME) ||
15518887b57dSGirish Moodalbail 	    nvlist_exists(db_nvl, IPADM_NVP_AOBJNAME)) {
15528887b57dSGirish Moodalbail 		return (B_TRUE);
15538887b57dSGirish Moodalbail 	}
15548887b57dSGirish Moodalbail 	assert(nvlist_exists(db_nvl, IPADM_NVP_PROTONAME));
15558887b57dSGirish Moodalbail 
15568887b57dSGirish Moodalbail 	/*
15578887b57dSGirish Moodalbail 	 * extract the propname from the `db_nvl' and also extract the
15588887b57dSGirish Moodalbail 	 * protocol from the `db_nvl'.
15598887b57dSGirish Moodalbail 	 */
15608887b57dSGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
15618887b57dSGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
15628887b57dSGirish Moodalbail 		name = nvpair_name(nvp);
15638887b57dSGirish Moodalbail 		if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
15648887b57dSGirish Moodalbail 			if (nvpair_value_string(nvp, &protostr) != 0)
15658887b57dSGirish Moodalbail 				return (B_TRUE);
15668887b57dSGirish Moodalbail 		} else {
15678887b57dSGirish Moodalbail 			assert(!IPADM_PRIV_NVP(name));
15688887b57dSGirish Moodalbail 			pname = name;
15698887b57dSGirish Moodalbail 			if (nvpair_value_string(nvp, &pval) != 0)
15708887b57dSGirish Moodalbail 				return (B_TRUE);
15718887b57dSGirish Moodalbail 		}
15728887b57dSGirish Moodalbail 	}
15738887b57dSGirish Moodalbail 
15748887b57dSGirish Moodalbail 	/* if the private property is in the right format return */
15758887b57dSGirish Moodalbail 	if (strncmp(pname, IPADM_PERSIST_PRIVPROP_PREFIX,
15768887b57dSGirish Moodalbail 	    strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
15778887b57dSGirish Moodalbail 		return (B_TRUE);
15788887b57dSGirish Moodalbail 	}
15798887b57dSGirish Moodalbail 	/* if it's a public property move onto the next property */
15808887b57dSGirish Moodalbail 	nproto = proto = ipadm_str2proto(protostr);
15818887b57dSGirish Moodalbail 	if (ipadm_legacy2new_propname(pname, nname, sizeof (nname),
15828887b57dSGirish Moodalbail 	    &nproto) != 0) {
15838887b57dSGirish Moodalbail 		return (B_TRUE);
15848887b57dSGirish Moodalbail 	}
15858887b57dSGirish Moodalbail 
15868887b57dSGirish Moodalbail 	/* replace the old protocol with new protocol, if required */
15878887b57dSGirish Moodalbail 	if (nproto != proto) {
15888887b57dSGirish Moodalbail 		protostr = ipadm_proto2str(nproto);
15898887b57dSGirish Moodalbail 		if (nvlist_add_string(db_nvl, IPADM_NVP_PROTONAME,
15908887b57dSGirish Moodalbail 		    protostr) != 0) {
15918887b57dSGirish Moodalbail 			return (B_TRUE);
15928887b57dSGirish Moodalbail 		}
15938887b57dSGirish Moodalbail 	}
15948887b57dSGirish Moodalbail 
15958887b57dSGirish Moodalbail 	/* replace the old property name with new property name, if required */
15968887b57dSGirish Moodalbail 	/* add the prefix to property name */
15978887b57dSGirish Moodalbail 	(void) snprintf(tmpstr, sizeof (tmpstr), "_%s", nname);
15988887b57dSGirish Moodalbail 	if (nvlist_add_string(db_nvl, tmpstr, pval) != 0 ||
15998887b57dSGirish Moodalbail 	    nvlist_remove(db_nvl, pname, DATA_TYPE_STRING) != 0) {
16008887b57dSGirish Moodalbail 		return (B_TRUE);
16018887b57dSGirish Moodalbail 	}
16028887b57dSGirish Moodalbail 	(void) memset(buf, 0, buflen);
16038887b57dSGirish Moodalbail 	if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
16048887b57dSGirish Moodalbail 		/* buffer overflow */
16058887b57dSGirish Moodalbail 		*errp = ENOBUFS;
16068887b57dSGirish Moodalbail 	}
16078887b57dSGirish Moodalbail 	return (B_TRUE);
16088887b57dSGirish Moodalbail }
1609550b6e40SSowmini Varadhan 
1610550b6e40SSowmini Varadhan /*
16118887b57dSGirish Moodalbail  * Called during boot.
16128887b57dSGirish Moodalbail  *
16138887b57dSGirish Moodalbail  * Walk through the DB and apply all the global module properties. We plow
16148887b57dSGirish Moodalbail  * through the DB even if we fail to apply property.
1615550b6e40SSowmini Varadhan  */
16168887b57dSGirish Moodalbail /* ARGSUSED */
16178887b57dSGirish Moodalbail static boolean_t
ipmgmt_db_init(void * cbarg,nvlist_t * db_nvl,char * buf,size_t buflen,int * errp)16188887b57dSGirish Moodalbail ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
16198887b57dSGirish Moodalbail     int *errp)
16208887b57dSGirish Moodalbail {
16218887b57dSGirish Moodalbail 	ipadm_handle_t	iph = cbarg;
1622a73be61aSHans Rosenfeld 	nvpair_t	*nvp, *pnvp = NULL;
16238887b57dSGirish Moodalbail 	char		*strval = NULL, *name, *mod = NULL, *pname;
16248887b57dSGirish Moodalbail 	char		tmpstr[IPMGMT_STRSIZE];
16258887b57dSGirish Moodalbail 	uint_t		proto;
16268887b57dSGirish Moodalbail 
16278887b57dSGirish Moodalbail 	/*
16288887b57dSGirish Moodalbail 	 * We could have used nvl_exists() directly, however we need several
16298887b57dSGirish Moodalbail 	 * calls to it and each call traverses the list. Since this codepath
16308887b57dSGirish Moodalbail 	 * is exercised during boot, let's traverse the list ourselves and do
16318887b57dSGirish Moodalbail 	 * the necessary checks.
16328887b57dSGirish Moodalbail 	 */
16338887b57dSGirish Moodalbail 	for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
16348887b57dSGirish Moodalbail 	    nvp = nvlist_next_nvpair(db_nvl, nvp)) {
16358887b57dSGirish Moodalbail 		name = nvpair_name(nvp);
16368887b57dSGirish Moodalbail 		if (IPADM_PRIV_NVP(name)) {
16378887b57dSGirish Moodalbail 			if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
16388887b57dSGirish Moodalbail 			    strcmp(name, IPADM_NVP_AOBJNAME) == 0)
16398887b57dSGirish Moodalbail 				return (B_TRUE);
16408887b57dSGirish Moodalbail 			else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
16418887b57dSGirish Moodalbail 			    nvpair_value_string(nvp, &mod) != 0)
16428887b57dSGirish Moodalbail 				return (B_TRUE);
16438887b57dSGirish Moodalbail 		} else {
16448887b57dSGirish Moodalbail 			/* possible a property */
16458887b57dSGirish Moodalbail 			pnvp = nvp;
16468887b57dSGirish Moodalbail 		}
16478887b57dSGirish Moodalbail 	}
16488887b57dSGirish Moodalbail 
1649a73be61aSHans Rosenfeld 	/* If we are here then we have found a global property */
16508887b57dSGirish Moodalbail 	assert(mod != NULL);
16518887b57dSGirish Moodalbail 	assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
16528887b57dSGirish Moodalbail 
16538887b57dSGirish Moodalbail 	proto = ipadm_str2proto(mod);
16548887b57dSGirish Moodalbail 	name = nvpair_name(pnvp);
16558887b57dSGirish Moodalbail 	if (nvpair_value_string(pnvp, &strval) == 0) {
16568887b57dSGirish Moodalbail 		if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
16578887b57dSGirish Moodalbail 		    strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
16588887b57dSGirish Moodalbail 			/* private protocol property */
16598887b57dSGirish Moodalbail 			pname = &name[1];
16608887b57dSGirish Moodalbail 		} else if (ipadm_legacy2new_propname(name, tmpstr,
16618887b57dSGirish Moodalbail 		    sizeof (tmpstr), &proto) == 0) {
16628887b57dSGirish Moodalbail 			pname = tmpstr;
16638887b57dSGirish Moodalbail 		} else {
16648887b57dSGirish Moodalbail 			pname = name;
16658887b57dSGirish Moodalbail 		}
16668887b57dSGirish Moodalbail 		if (ipadm_set_prop(iph, pname, strval, proto,
16678887b57dSGirish Moodalbail 		    IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
16688887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
16698887b57dSGirish Moodalbail 			    pname);
16708887b57dSGirish Moodalbail 		}
16718887b57dSGirish Moodalbail 	}
16728887b57dSGirish Moodalbail 
16738887b57dSGirish Moodalbail 	return (B_TRUE);
16748887b57dSGirish Moodalbail }
16758887b57dSGirish Moodalbail 
16768887b57dSGirish Moodalbail /* initialize global module properties */
16778887b57dSGirish Moodalbail void
ipmgmt_init_prop()16788887b57dSGirish Moodalbail ipmgmt_init_prop()
16798887b57dSGirish Moodalbail {
16808887b57dSGirish Moodalbail 	ipadm_handle_t	iph = NULL;
16818887b57dSGirish Moodalbail 
16828887b57dSGirish Moodalbail 	if (ipadm_open(&iph, IPH_INIT) != IPADM_SUCCESS) {
16838887b57dSGirish Moodalbail 		ipmgmt_log(LOG_WARNING, "Could not reapply any of the "
16848887b57dSGirish Moodalbail 		    "persisted protocol properties");
16858887b57dSGirish Moodalbail 		return;
16868887b57dSGirish Moodalbail 	}
16878887b57dSGirish Moodalbail 	/* ipmgmt_db_init() logs warnings if there are any issues */
16888887b57dSGirish Moodalbail 	(void) ipmgmt_db_walk(ipmgmt_db_init, iph, IPADM_DB_READ);
16898887b57dSGirish Moodalbail 	ipadm_close(iph);
16908887b57dSGirish Moodalbail }
16918887b57dSGirish Moodalbail 
16928887b57dSGirish Moodalbail void
ipmgmt_release_scf_resources(scf_resources_t * res)1693550b6e40SSowmini Varadhan ipmgmt_release_scf_resources(scf_resources_t *res)
1694550b6e40SSowmini Varadhan {
1695550b6e40SSowmini Varadhan 	scf_entry_destroy(res->sr_ent);
1696550b6e40SSowmini Varadhan 	scf_transaction_destroy(res->sr_tx);
1697550b6e40SSowmini Varadhan 	scf_value_destroy(res->sr_val);
1698550b6e40SSowmini Varadhan 	scf_property_destroy(res->sr_prop);
1699550b6e40SSowmini Varadhan 	scf_pg_destroy(res->sr_pg);
1700550b6e40SSowmini Varadhan 	scf_instance_destroy(res->sr_inst);
1701550b6e40SSowmini Varadhan 	(void) scf_handle_unbind(res->sr_handle);
1702550b6e40SSowmini Varadhan 	scf_handle_destroy(res->sr_handle);
1703550b6e40SSowmini Varadhan }
1704550b6e40SSowmini Varadhan 
1705550b6e40SSowmini Varadhan /*
17068887b57dSGirish Moodalbail  * It creates the necessary SCF handles and binds the given `fmri' to an
17078887b57dSGirish Moodalbail  * instance. These resources are required for retrieving property value,
17088887b57dSGirish Moodalbail  * creating property groups and modifying property values.
1709550b6e40SSowmini Varadhan  */
17108887b57dSGirish Moodalbail int
ipmgmt_create_scf_resources(const char * fmri,scf_resources_t * res)1711550b6e40SSowmini Varadhan ipmgmt_create_scf_resources(const char *fmri, scf_resources_t *res)
1712550b6e40SSowmini Varadhan {
1713550b6e40SSowmini Varadhan 	res->sr_tx = NULL;
1714550b6e40SSowmini Varadhan 	res->sr_ent = NULL;
1715550b6e40SSowmini Varadhan 	res->sr_inst = NULL;
1716550b6e40SSowmini Varadhan 	res->sr_pg = NULL;
1717550b6e40SSowmini Varadhan 	res->sr_prop = NULL;
1718550b6e40SSowmini Varadhan 	res->sr_val = NULL;
1719550b6e40SSowmini Varadhan 
17208887b57dSGirish Moodalbail 	if ((res->sr_handle = scf_handle_create(SCF_VERSION)) == NULL)
1721550b6e40SSowmini Varadhan 		return (-1);
1722550b6e40SSowmini Varadhan 
1723550b6e40SSowmini Varadhan 	if (scf_handle_bind(res->sr_handle) != 0) {
1724550b6e40SSowmini Varadhan 		scf_handle_destroy(res->sr_handle);
1725550b6e40SSowmini Varadhan 		return (-1);
1726550b6e40SSowmini Varadhan 	}
17278887b57dSGirish Moodalbail 	if ((res->sr_inst = scf_instance_create(res->sr_handle)) == NULL)
1728550b6e40SSowmini Varadhan 		goto failure;
1729550b6e40SSowmini Varadhan 	if (scf_handle_decode_fmri(res->sr_handle, fmri, NULL, NULL,
1730550b6e40SSowmini Varadhan 	    res->sr_inst, NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
1731550b6e40SSowmini Varadhan 		goto failure;
1732550b6e40SSowmini Varadhan 	}
17338887b57dSGirish Moodalbail 	/* we will create the rest of the resources on demand */
1734550b6e40SSowmini Varadhan 	return (0);
1735550b6e40SSowmini Varadhan 
1736550b6e40SSowmini Varadhan failure:
17378887b57dSGirish Moodalbail 	ipmgmt_log(LOG_WARNING, "failed to create scf resources: %s",
17388887b57dSGirish Moodalbail 	    scf_strerror(scf_error()));
1739550b6e40SSowmini Varadhan 	ipmgmt_release_scf_resources(res);
1740550b6e40SSowmini Varadhan 	return (-1);
1741550b6e40SSowmini Varadhan }
1742550b6e40SSowmini Varadhan 
17438887b57dSGirish Moodalbail /*
17448887b57dSGirish Moodalbail  * persists the `pval' for a given property `pname' in SCF. The only supported
17458887b57dSGirish Moodalbail  * SCF property types are INTEGER and ASTRING.
17468887b57dSGirish Moodalbail  */
1747550b6e40SSowmini Varadhan static int
ipmgmt_set_scfprop_value(scf_resources_t * res,const char * pname,void * pval,scf_type_t ptype)17488887b57dSGirish Moodalbail ipmgmt_set_scfprop_value(scf_resources_t *res, const char *pname, void *pval,
17498887b57dSGirish Moodalbail     scf_type_t ptype)
1750550b6e40SSowmini Varadhan {
1751550b6e40SSowmini Varadhan 	int result = -1;
1752550b6e40SSowmini Varadhan 	boolean_t new;
1753550b6e40SSowmini Varadhan 
17548887b57dSGirish Moodalbail 	if ((res->sr_val = scf_value_create(res->sr_handle)) == NULL)
17558887b57dSGirish Moodalbail 		goto failure;
17568887b57dSGirish Moodalbail 	switch (ptype) {
17578887b57dSGirish Moodalbail 	case SCF_TYPE_INTEGER:
17588887b57dSGirish Moodalbail 		scf_value_set_integer(res->sr_val, *(int64_t *)pval);
17598887b57dSGirish Moodalbail 		break;
17608887b57dSGirish Moodalbail 	case SCF_TYPE_ASTRING:
17618887b57dSGirish Moodalbail 		if (scf_value_set_astring(res->sr_val, (char *)pval) != 0) {
17628887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Error setting string value %s "
17638887b57dSGirish Moodalbail 			    "for property %s: %s", pval, pname,
17648887b57dSGirish Moodalbail 			    scf_strerror(scf_error()));
17658887b57dSGirish Moodalbail 			goto failure;
17668887b57dSGirish Moodalbail 		}
17678887b57dSGirish Moodalbail 		break;
17688887b57dSGirish Moodalbail 	default:
1769550b6e40SSowmini Varadhan 		goto failure;
1770550b6e40SSowmini Varadhan 	}
17718887b57dSGirish Moodalbail 
17728887b57dSGirish Moodalbail 	if ((res->sr_tx = scf_transaction_create(res->sr_handle)) == NULL)
17738887b57dSGirish Moodalbail 		goto failure;
17748887b57dSGirish Moodalbail 	if ((res->sr_ent = scf_entry_create(res->sr_handle)) == NULL)
17758887b57dSGirish Moodalbail 		goto failure;
17768887b57dSGirish Moodalbail 	if ((res->sr_prop = scf_property_create(res->sr_handle)) == NULL)
17778887b57dSGirish Moodalbail 		goto failure;
17788887b57dSGirish Moodalbail 
17798887b57dSGirish Moodalbail retry:
17808887b57dSGirish Moodalbail 	new = (scf_pg_get_property(res->sr_pg, pname, res->sr_prop) != 0);
17818887b57dSGirish Moodalbail 	if (scf_transaction_start(res->sr_tx, res->sr_pg) == -1)
17828887b57dSGirish Moodalbail 		goto failure;
1783550b6e40SSowmini Varadhan 	if (new) {
1784550b6e40SSowmini Varadhan 		if (scf_transaction_property_new(res->sr_tx, res->sr_ent,
17858887b57dSGirish Moodalbail 		    pname, ptype) == -1) {
1786550b6e40SSowmini Varadhan 			goto failure;
1787550b6e40SSowmini Varadhan 		}
1788550b6e40SSowmini Varadhan 	} else {
1789550b6e40SSowmini Varadhan 		if (scf_transaction_property_change(res->sr_tx, res->sr_ent,
17908887b57dSGirish Moodalbail 		    pname, ptype) == -1) {
1791550b6e40SSowmini Varadhan 			goto failure;
1792550b6e40SSowmini Varadhan 		}
1793550b6e40SSowmini Varadhan 	}
1794550b6e40SSowmini Varadhan 
17958887b57dSGirish Moodalbail 	if (scf_entry_add_value(res->sr_ent, res->sr_val) != 0)
1796550b6e40SSowmini Varadhan 		goto failure;
1797550b6e40SSowmini Varadhan 
1798550b6e40SSowmini Varadhan 	result = scf_transaction_commit(res->sr_tx);
1799550b6e40SSowmini Varadhan 	if (result == 0) {
1800550b6e40SSowmini Varadhan 		scf_transaction_reset(res->sr_tx);
1801550b6e40SSowmini Varadhan 		if (scf_pg_update(res->sr_pg) == -1) {
1802550b6e40SSowmini Varadhan 			goto failure;
1803550b6e40SSowmini Varadhan 		}
1804550b6e40SSowmini Varadhan 		goto retry;
1805550b6e40SSowmini Varadhan 	}
1806550b6e40SSowmini Varadhan 	if (result == -1)
1807550b6e40SSowmini Varadhan 		goto failure;
1808550b6e40SSowmini Varadhan 	return (0);
1809550b6e40SSowmini Varadhan 
1810550b6e40SSowmini Varadhan failure:
18118887b57dSGirish Moodalbail 	ipmgmt_log(LOG_WARNING, "failed to save the data in SCF: %s",
18128887b57dSGirish Moodalbail 	    scf_strerror(scf_error()));
1813550b6e40SSowmini Varadhan 	return (-1);
1814550b6e40SSowmini Varadhan }
1815550b6e40SSowmini Varadhan 
1816550b6e40SSowmini Varadhan /*
18178887b57dSGirish Moodalbail  * Given a `pgname'/`pname', it retrieves the value based on `ptype' and
18188887b57dSGirish Moodalbail  * places it in `pval'.
1819550b6e40SSowmini Varadhan  */
18208887b57dSGirish Moodalbail static int
ipmgmt_get_scfprop(scf_resources_t * res,const char * pgname,const char * pname,void * pval,scf_type_t ptype)18218887b57dSGirish Moodalbail ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
18228887b57dSGirish Moodalbail     void *pval, scf_type_t ptype)
1823550b6e40SSowmini Varadhan {
18248887b57dSGirish Moodalbail 	ssize_t		numvals;
1825550b6e40SSowmini Varadhan 	scf_simple_prop_t *prop;
1826550b6e40SSowmini Varadhan 
18278887b57dSGirish Moodalbail 	prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1828550b6e40SSowmini Varadhan 	numvals = scf_simple_prop_numvalues(prop);
18298887b57dSGirish Moodalbail 	if (numvals <= 0)
18308887b57dSGirish Moodalbail 		goto ret;
18318887b57dSGirish Moodalbail 	switch (ptype) {
18328887b57dSGirish Moodalbail 	case SCF_TYPE_INTEGER:
18338887b57dSGirish Moodalbail 		*(int64_t **)pval = scf_simple_prop_next_integer(prop);
18348887b57dSGirish Moodalbail 		break;
18358887b57dSGirish Moodalbail 	case SCF_TYPE_ASTRING:
18368887b57dSGirish Moodalbail 		*(char **)pval = scf_simple_prop_next_astring(prop);
18378887b57dSGirish Moodalbail 		break;
1838a73be61aSHans Rosenfeld 	default:
1839a73be61aSHans Rosenfeld 		break;
1840550b6e40SSowmini Varadhan 	}
18418887b57dSGirish Moodalbail ret:
18428887b57dSGirish Moodalbail 	scf_simple_prop_free(prop);
18438887b57dSGirish Moodalbail 	return (numvals);
18448887b57dSGirish Moodalbail }
1845550b6e40SSowmini Varadhan 
18468887b57dSGirish Moodalbail /*
18478887b57dSGirish Moodalbail  * It stores the `pval' for given `pgname'/`pname' property group in SCF.
18488887b57dSGirish Moodalbail  */
18498887b57dSGirish Moodalbail static int
ipmgmt_set_scfprop(scf_resources_t * res,const char * pgname,const char * pname,void * pval,scf_type_t ptype)18508887b57dSGirish Moodalbail ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
18518887b57dSGirish Moodalbail     void *pval, scf_type_t ptype)
18528887b57dSGirish Moodalbail {
18538887b57dSGirish Moodalbail 	scf_error_t		err;
18548887b57dSGirish Moodalbail 
18558887b57dSGirish Moodalbail 	if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
18568887b57dSGirish Moodalbail 		ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
18578887b57dSGirish Moodalbail 		    scf_strerror(scf_error()));
18588887b57dSGirish Moodalbail 		return (-1);
18598887b57dSGirish Moodalbail 	}
18608887b57dSGirish Moodalbail 
18618887b57dSGirish Moodalbail 	if (scf_instance_add_pg(res->sr_inst, pgname, SCF_GROUP_APPLICATION,
18628887b57dSGirish Moodalbail 	    0, res->sr_pg) != 0) {
18638887b57dSGirish Moodalbail 		if ((err = scf_error()) != SCF_ERROR_EXISTS) {
18648887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING,
18658887b57dSGirish Moodalbail 			    "Error adding property group '%s/%s': %s",
18668887b57dSGirish Moodalbail 			    pgname, pname, scf_strerror(err));
18678887b57dSGirish Moodalbail 			return (-1);
18688887b57dSGirish Moodalbail 		}
1869550b6e40SSowmini Varadhan 		/*
18708887b57dSGirish Moodalbail 		 * if the property group already exists, then we get the
18718887b57dSGirish Moodalbail 		 * composed view of the property group for the given instance.
1872550b6e40SSowmini Varadhan 		 */
18738887b57dSGirish Moodalbail 		if (scf_instance_get_pg_composed(res->sr_inst, NULL, pgname,
18748887b57dSGirish Moodalbail 		    res->sr_pg) != 0) {
18758887b57dSGirish Moodalbail 			ipmgmt_log(LOG_WARNING, "Error getting composed view "
18768887b57dSGirish Moodalbail 			    "of the property group '%s/%s': %s", pgname, pname,
18778887b57dSGirish Moodalbail 			    scf_strerror(scf_error()));
18788887b57dSGirish Moodalbail 			return (-1);
1879550b6e40SSowmini Varadhan 		}
1880550b6e40SSowmini Varadhan 	}
1881550b6e40SSowmini Varadhan 
18828887b57dSGirish Moodalbail 	return (ipmgmt_set_scfprop_value(res, pname, pval, ptype));
18838887b57dSGirish Moodalbail }
18848887b57dSGirish Moodalbail 
18858887b57dSGirish Moodalbail /*
18868887b57dSGirish Moodalbail  * Returns B_TRUE, if the non-global zone is being booted for the first time
18878887b57dSGirish Moodalbail  * after being installed. This is required to setup the ipadm data-store for
18888887b57dSGirish Moodalbail  * the first boot of the non-global zone. Please see, PSARC 2010/166,
18898887b57dSGirish Moodalbail  * for more info.
18908887b57dSGirish Moodalbail  *
18918887b57dSGirish Moodalbail  * Note that, this API cannot be used to determine first boot post image-update.
18928887b57dSGirish Moodalbail  * 'pkg image-update' clones the current BE and the existing value of
18938887b57dSGirish Moodalbail  * ipmgmtd/first_boot_done will be carried forward and obviously it will be set
18948887b57dSGirish Moodalbail  * to B_TRUE.
18958887b57dSGirish Moodalbail  */
18968887b57dSGirish Moodalbail boolean_t
ipmgmt_ngz_firstboot_postinstall()18978887b57dSGirish Moodalbail ipmgmt_ngz_firstboot_postinstall()
18988887b57dSGirish Moodalbail {
18998887b57dSGirish Moodalbail 	scf_resources_t	res;
19008887b57dSGirish Moodalbail 	boolean_t	bval = B_TRUE;
19018887b57dSGirish Moodalbail 	char		*strval;
19028887b57dSGirish Moodalbail 
19038887b57dSGirish Moodalbail 	/* we always err on the side of caution */
19048887b57dSGirish Moodalbail 	if (ipmgmt_create_scf_resources(IPMGMTD_FMRI, &res) != 0)
19058887b57dSGirish Moodalbail 		return (bval);
19068887b57dSGirish Moodalbail 
19078887b57dSGirish Moodalbail 	if (ipmgmt_get_scfprop(&res, IPMGMTD_APP_PG, IPMGMTD_PROP_FBD, &strval,
19088887b57dSGirish Moodalbail 	    SCF_TYPE_ASTRING) > 0) {
19098887b57dSGirish Moodalbail 		bval = (strcmp(strval, IPMGMTD_TRUESTR) == 0 ?
19108887b57dSGirish Moodalbail 		    B_FALSE : B_TRUE);
19118887b57dSGirish Moodalbail 	} else {
19128887b57dSGirish Moodalbail 		/*
19138887b57dSGirish Moodalbail 		 * IPMGMTD_PROP_FBD does not exist in the SCF. Lets create it.
19148887b57dSGirish Moodalbail 		 * Since we err on the side of caution, we ignore the return
19158887b57dSGirish Moodalbail 		 * error and return B_TRUE.
19168887b57dSGirish Moodalbail 		 */
19178887b57dSGirish Moodalbail 		(void) ipmgmt_set_scfprop(&res, IPMGMTD_APP_PG,
19188887b57dSGirish Moodalbail 		    IPMGMTD_PROP_FBD, IPMGMTD_TRUESTR, SCF_TYPE_ASTRING);
1919550b6e40SSowmini Varadhan 	}
19208887b57dSGirish Moodalbail 	ipmgmt_release_scf_resources(&res);
19218887b57dSGirish Moodalbail 	return (bval);
19228887b57dSGirish Moodalbail }
19238887b57dSGirish Moodalbail 
19248887b57dSGirish Moodalbail /*
19258887b57dSGirish Moodalbail  * Returns B_TRUE, if the data-store needs upgrade otherwise returns B_FALSE.
19268887b57dSGirish Moodalbail  * Today we have to take care of, one case of, upgrading from version 0 to
19278887b57dSGirish Moodalbail  * version 1, so we will use boolean_t as means to decide if upgrade is needed
19288887b57dSGirish Moodalbail  * or not. Further, the upcoming projects might completely move the flatfile
19298887b57dSGirish Moodalbail  * data-store into SCF and hence we shall keep this interface simple.
19308887b57dSGirish Moodalbail  */
19318887b57dSGirish Moodalbail boolean_t
ipmgmt_needs_upgrade(scf_resources_t * res)19328887b57dSGirish Moodalbail ipmgmt_needs_upgrade(scf_resources_t *res)
19338887b57dSGirish Moodalbail {
19348887b57dSGirish Moodalbail 	boolean_t	bval = B_TRUE;
19358887b57dSGirish Moodalbail 	int64_t		*verp;
1936550b6e40SSowmini Varadhan 
19378887b57dSGirish Moodalbail 	if (ipmgmt_get_scfprop(res, IPMGMTD_APP_PG, IPMGMTD_PROP_DBVER,
19388887b57dSGirish Moodalbail 	    &verp, SCF_TYPE_INTEGER) > 0) {
19398887b57dSGirish Moodalbail 		if (*verp == IPADM_DB_VERSION)
19408887b57dSGirish Moodalbail 			bval = B_FALSE;
1941550b6e40SSowmini Varadhan 	}
19428887b57dSGirish Moodalbail 	/*
19438887b57dSGirish Moodalbail 	 * 'datastore_version' doesn't exist. Which means that we need to
19448887b57dSGirish Moodalbail 	 * upgrade the datastore. We will create 'datastore_version' and set
19458887b57dSGirish Moodalbail 	 * the version value to IPADM_DB_VERSION, after we upgrade the file.
19468887b57dSGirish Moodalbail 	 */
19478887b57dSGirish Moodalbail 	return (bval);
19488887b57dSGirish Moodalbail }
1949550b6e40SSowmini Varadhan 
19508887b57dSGirish Moodalbail /*
19518887b57dSGirish Moodalbail  * This is called after the successful upgrade of the local data-store. With
19528887b57dSGirish Moodalbail  * the data-store upgraded to recent version we don't have to do anything on
19538887b57dSGirish Moodalbail  * subsequent reboots.
19548887b57dSGirish Moodalbail  */
19558887b57dSGirish Moodalbail void
ipmgmt_update_dbver(scf_resources_t * res)19568887b57dSGirish Moodalbail ipmgmt_update_dbver(scf_resources_t *res)
19578887b57dSGirish Moodalbail {
19588887b57dSGirish Moodalbail 	int64_t		version = IPADM_DB_VERSION;
19598887b57dSGirish Moodalbail 
19608887b57dSGirish Moodalbail 	(void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
19618887b57dSGirish Moodalbail 	    IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1962550b6e40SSowmini Varadhan }
1963a73be61aSHans Rosenfeld 
1964a73be61aSHans Rosenfeld /*
1965a73be61aSHans Rosenfeld  * Return TRUE if `ifname' has persistent configuration for the `af' address
1966a73be61aSHans Rosenfeld  * family in the datastore.
1967a73be61aSHans Rosenfeld  * It is possible to call the function with af == AF_UNSPEC, so in this case
1968a73be61aSHans Rosenfeld  * the function returns TRUE if either AF_INET or AF_INET6 interface exists
1969a73be61aSHans Rosenfeld  */
1970a73be61aSHans Rosenfeld boolean_t
ipmgmt_persist_if_exists(const char * ifname,sa_family_t af)1971a73be61aSHans Rosenfeld ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
1972a73be61aSHans Rosenfeld {
1973a73be61aSHans Rosenfeld 	boolean_t exists = B_FALSE;
1974a73be61aSHans Rosenfeld 	nvlist_t    *if_info_nvl;
1975a73be61aSHans Rosenfeld 	uint16_t    *families = NULL;
1976a73be61aSHans Rosenfeld 	sa_family_t af_db;
1977a73be61aSHans Rosenfeld 	uint_t	nelem = 0;
1978a73be61aSHans Rosenfeld 
1979a73be61aSHans Rosenfeld 	if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
1980a73be61aSHans Rosenfeld 		goto done;
1981a73be61aSHans Rosenfeld 
1982a73be61aSHans Rosenfeld 	if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
1983a73be61aSHans Rosenfeld 	    &families, &nelem) != 0)
1984a73be61aSHans Rosenfeld 		goto done;
1985a73be61aSHans Rosenfeld 
1986a73be61aSHans Rosenfeld 	while (nelem-- > 0) {
1987a73be61aSHans Rosenfeld 		af_db = families[nelem];
1988a73be61aSHans Rosenfeld 		if (af_db == af || (af == AF_UNSPEC &&
1989a73be61aSHans Rosenfeld 		    (af_db == AF_INET || af_db == AF_INET6))) {
1990a73be61aSHans Rosenfeld 			exists = B_TRUE;
1991a73be61aSHans Rosenfeld 			break;
1992a73be61aSHans Rosenfeld 		}
1993a73be61aSHans Rosenfeld 	}
1994a73be61aSHans Rosenfeld 
1995a73be61aSHans Rosenfeld done:
1996a73be61aSHans Rosenfeld 	if (if_info_nvl != NULL)
1997a73be61aSHans Rosenfeld 		nvlist_free(if_info_nvl);
1998a73be61aSHans Rosenfeld 
1999a73be61aSHans Rosenfeld 	return (exists);
2000a73be61aSHans Rosenfeld }
2001a73be61aSHans Rosenfeld 
2002a73be61aSHans Rosenfeld /*
2003a73be61aSHans Rosenfeld  * Retrieves the membership information for the requested mif_name
2004a73be61aSHans Rosenfeld  * if mif_name is a member of a IPMP group, then gif_name will contain
2005a73be61aSHans Rosenfeld  * the name of IPMP group interface, otherwise the variable will be empty
2006a73be61aSHans Rosenfeld  */
2007a73be61aSHans Rosenfeld void
ipmgmt_get_group_interface(const char * mif_name,char * gif_name,size_t size)2008a73be61aSHans Rosenfeld ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
2009a73be61aSHans Rosenfeld {
2010a73be61aSHans Rosenfeld 	char	*gif_name_from_nvl;
2011a73be61aSHans Rosenfeld 	nvlist_t	*if_info_nvl;
2012a73be61aSHans Rosenfeld 
2013a73be61aSHans Rosenfeld 	gif_name[0] = '\0';
2014a73be61aSHans Rosenfeld 
2015a73be61aSHans Rosenfeld 	if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
2016a73be61aSHans Rosenfeld 		goto done;
2017a73be61aSHans Rosenfeld 
2018a73be61aSHans Rosenfeld 	if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
2019a73be61aSHans Rosenfeld 	    &gif_name_from_nvl) != 0)
2020a73be61aSHans Rosenfeld 		goto done;
2021a73be61aSHans Rosenfeld 
2022a73be61aSHans Rosenfeld 	(void) strlcpy(gif_name, gif_name_from_nvl, size);
2023a73be61aSHans Rosenfeld 
2024a73be61aSHans Rosenfeld done:
2025a73be61aSHans Rosenfeld 	if (if_info_nvl != NULL)
2026a73be61aSHans Rosenfeld 		nvlist_free(if_info_nvl);
2027a73be61aSHans Rosenfeld }
2028a73be61aSHans Rosenfeld 
2029a73be61aSHans Rosenfeld static int
ipmgmt_get_ifinfo_nvl(const char * ifname,nvlist_t ** if_info_nvl)2030a73be61aSHans Rosenfeld ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
2031a73be61aSHans Rosenfeld {
2032a73be61aSHans Rosenfeld 	ipmgmt_get_cbarg_t cbarg;
2033a73be61aSHans Rosenfeld 	nvpair_t    *nvp;
2034a73be61aSHans Rosenfeld 	nvlist_t    *nvl;
2035a73be61aSHans Rosenfeld 	int	err;
2036a73be61aSHans Rosenfeld 
2037a73be61aSHans Rosenfeld 	cbarg.cb_ifname = NULL;
2038a73be61aSHans Rosenfeld 	cbarg.cb_aobjname = NULL;
2039a73be61aSHans Rosenfeld 	cbarg.cb_ocnt = 0;
2040a73be61aSHans Rosenfeld 
204147c607a3SAndy Fiddaman 	*if_info_nvl = NULL;
204247c607a3SAndy Fiddaman 
2043a73be61aSHans Rosenfeld 	if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
2044a73be61aSHans Rosenfeld 		goto done;
2045a73be61aSHans Rosenfeld 
2046a73be61aSHans Rosenfeld 	err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
2047a73be61aSHans Rosenfeld 	if (err == ENOENT && cbarg.cb_ocnt > 0)
2048a73be61aSHans Rosenfeld 		err = 0;
2049a73be61aSHans Rosenfeld 
2050a73be61aSHans Rosenfeld 	if (err != 0)
2051a73be61aSHans Rosenfeld 		goto done;
2052a73be61aSHans Rosenfeld 
2053a73be61aSHans Rosenfeld 	for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
2054a73be61aSHans Rosenfeld 	    nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
2055a73be61aSHans Rosenfeld 
2056a73be61aSHans Rosenfeld 		if (strcmp(nvpair_name(nvp), ifname) != 0)
2057a73be61aSHans Rosenfeld 			continue;
2058a73be61aSHans Rosenfeld 
2059a73be61aSHans Rosenfeld 		if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
2060a73be61aSHans Rosenfeld 		    (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
2061a73be61aSHans Rosenfeld 			*if_info_nvl = NULL;
2062a73be61aSHans Rosenfeld 
2063a73be61aSHans Rosenfeld 		break;
2064a73be61aSHans Rosenfeld 	}
2065a73be61aSHans Rosenfeld 
2066a73be61aSHans Rosenfeld done:
2067a73be61aSHans Rosenfeld 	nvlist_free(cbarg.cb_onvl);
2068a73be61aSHans Rosenfeld 
2069a73be61aSHans Rosenfeld 	return (err);
2070a73be61aSHans Rosenfeld }
2071