13147Sxc151355 /*
23147Sxc151355  * CDDL HEADER START
33147Sxc151355  *
43147Sxc151355  * The contents of this file are subject to the terms of the
53147Sxc151355  * Common Development and Distribution License (the "License").
63147Sxc151355  * You may not use this file except in compliance with the License.
73147Sxc151355  *
83147Sxc151355  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93147Sxc151355  * or http://www.opensolaris.org/os/licensing.
103147Sxc151355  * See the License for the specific language governing permissions
113147Sxc151355  * and limitations under the License.
123147Sxc151355  *
133147Sxc151355  * When distributing Covered Code, include this CDDL HEADER in each
143147Sxc151355  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153147Sxc151355  * If applicable, add the following below this CDDL HEADER, with the
163147Sxc151355  * fields enclosed by brackets "[]" replaced with your own identifying
173147Sxc151355  * information: Portions Copyright [yyyy] [name of copyright owner]
183147Sxc151355  *
193147Sxc151355  * CDDL HEADER END
203147Sxc151355  */
213147Sxc151355 /*
22*3448Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
233147Sxc151355  * Use is subject to license terms.
243147Sxc151355  */
253147Sxc151355 
263147Sxc151355 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273147Sxc151355 
283147Sxc151355 #include <stdlib.h>
293147Sxc151355 #include <strings.h>
303147Sxc151355 #include <errno.h>
313147Sxc151355 #include <ctype.h>
32*3448Sdh155122 #include <sys/types.h>
333147Sxc151355 #include <sys/stat.h>
34*3448Sdh155122 #include <sys/dld.h>
35*3448Sdh155122 #include <sys/zone.h>
36*3448Sdh155122 #include <fcntl.h>
37*3448Sdh155122 #include <unistd.h>
38*3448Sdh155122 #include <libdevinfo.h>
39*3448Sdh155122 #include <zone.h>
403147Sxc151355 #include <libwladm.h>
413147Sxc151355 #include <libdladm_impl.h>
423147Sxc151355 
43*3448Sdh155122 #include <dlfcn.h>
44*3448Sdh155122 #include <link.h>
45*3448Sdh155122 
463147Sxc151355 static dladm_status_t	i_dladm_set_prop_db(const char *, const char *,
473147Sxc151355 			    char **, uint_t);
483147Sxc151355 static dladm_status_t	i_dladm_get_prop_db(const char *, const char *,
493147Sxc151355 			    char **, uint_t *);
50*3448Sdh155122 static dladm_status_t	i_dladm_get_prop_temp(const char *, dladm_prop_type_t,
51*3448Sdh155122 			    const char *, char **, uint_t *);
52*3448Sdh155122 static dladm_status_t	i_dladm_set_prop_temp(const char *, const char *,
53*3448Sdh155122 			    char **, uint_t, uint_t, char **);
54*3448Sdh155122 static boolean_t	i_dladm_is_prop_temponly(const char *prop_name,
55*3448Sdh155122 			    char **);
56*3448Sdh155122 
57*3448Sdh155122 typedef struct val_desc {
58*3448Sdh155122 	char	*vd_name;
59*3448Sdh155122 	void	*vd_val;
60*3448Sdh155122 } val_desc_t;
61*3448Sdh155122 
62*3448Sdh155122 struct prop_desc;
63*3448Sdh155122 
64*3448Sdh155122 typedef dladm_status_t	pd_getf_t(const char *, char **, uint_t *);
65*3448Sdh155122 typedef dladm_status_t	pd_setf_t(const char *, val_desc_t *, uint_t);
66*3448Sdh155122 typedef dladm_status_t	pd_checkf_t(struct prop_desc *, char **,
67*3448Sdh155122 			    uint_t, val_desc_t **);
68*3448Sdh155122 
69*3448Sdh155122 static pd_getf_t	do_get_zone;
70*3448Sdh155122 static pd_setf_t	do_set_zone;
71*3448Sdh155122 static pd_checkf_t	do_check_zone;
72*3448Sdh155122 
73*3448Sdh155122 typedef struct prop_desc {
74*3448Sdh155122 	char		*pd_name;
75*3448Sdh155122 	val_desc_t	pd_defval;
76*3448Sdh155122 	val_desc_t	*pd_modval;
77*3448Sdh155122 	uint_t		pd_nmodval;
78*3448Sdh155122 	boolean_t	pd_temponly;
79*3448Sdh155122 	pd_setf_t	*pd_set;
80*3448Sdh155122 	pd_getf_t	*pd_getmod;
81*3448Sdh155122 	pd_getf_t	*pd_get;
82*3448Sdh155122 	pd_checkf_t	*pd_check;
83*3448Sdh155122 } prop_desc_t;
84*3448Sdh155122 
85*3448Sdh155122 static prop_desc_t	prop_table[] = {
86*3448Sdh155122 	{ "zone",	{ "", NULL }, NULL, 0, B_TRUE,
87*3448Sdh155122 	    do_set_zone, NULL,
88*3448Sdh155122 	    do_get_zone, do_check_zone}
89*3448Sdh155122 };
90*3448Sdh155122 
91*3448Sdh155122 #define	MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
923147Sxc151355 
933147Sxc151355 /*
943147Sxc151355  * Convert a wladm_status_t to a dladm_status_t. This is used by wrappers
953147Sxc151355  * to libwladm routines (e.g. dladm_set_prop()). Note that the mapping is
963147Sxc151355  * not 1-1; whenever possible we try to look for an error code with a
973147Sxc151355  * similar meaning. Error codes with no suitable counterpart in libdladm
983147Sxc151355  * will be mapped to DLADM_STATUS_FAILED. Clients who require clearer error
993147Sxc151355  * reporting should use libwladm directly.
1003147Sxc151355  */
1013147Sxc151355 static dladm_status_t
1023147Sxc151355 dladm_wladmstatus2status(wladm_status_t wstatus)
1033147Sxc151355 {
1043147Sxc151355 	switch (wstatus) {
1053147Sxc151355 	case WLADM_STATUS_OK:
1063147Sxc151355 		return (DLADM_STATUS_OK);
1073147Sxc151355 	case WLADM_STATUS_FAILED:
1083147Sxc151355 		return (DLADM_STATUS_FAILED);
1093147Sxc151355 	case WLADM_STATUS_NOTSUP:
1103147Sxc151355 		return (DLADM_STATUS_NOTSUP);
1113147Sxc151355 	case WLADM_STATUS_BADARG:
1123147Sxc151355 		return (DLADM_STATUS_BADARG);
1133147Sxc151355 	case WLADM_STATUS_NOTFOUND:
1143147Sxc151355 		return (DLADM_STATUS_NOTFOUND);
1153147Sxc151355 	case WLADM_STATUS_BADVAL:
1163147Sxc151355 		return (DLADM_STATUS_BADVAL);
1173147Sxc151355 	case WLADM_STATUS_LINKINVAL:
1183147Sxc151355 		return (DLADM_STATUS_LINKINVAL);
1193147Sxc151355 	case WLADM_STATUS_NOMEM:
1203147Sxc151355 		return (DLADM_STATUS_NOMEM);
1213147Sxc151355 	case WLADM_STATUS_PROPRDONLY:
1223147Sxc151355 		return (DLADM_STATUS_PROPRDONLY);
1233147Sxc151355 	case WLADM_STATUS_TOOSMALL:
1243147Sxc151355 		return (DLADM_STATUS_TOOSMALL);
1253147Sxc151355 	case WLADM_STATUS_BADVALCNT:
1263147Sxc151355 		return (DLADM_STATUS_BADVALCNT);
1273147Sxc151355 	default:
1283147Sxc151355 		return (DLADM_STATUS_FAILED);
1293147Sxc151355 	}
1303147Sxc151355 }
1313147Sxc151355 
1323147Sxc151355 dladm_status_t
1333147Sxc151355 dladm_set_prop(const char *link, const char *prop_name, char **prop_val,
134*3448Sdh155122     uint_t val_cnt, uint_t flags, char **errprop)
1353147Sxc151355 {
1363147Sxc151355 	dladm_status_t		status = DLADM_STATUS_BADARG;
1373147Sxc151355 
1383147Sxc151355 	if (link == NULL || (prop_val == NULL && val_cnt > 0) ||
1393147Sxc151355 	    (prop_val != NULL && val_cnt == 0) || flags == 0)
1403147Sxc151355 		return (DLADM_STATUS_BADARG);
1413147Sxc151355 
1423147Sxc151355 	if ((flags & DLADM_OPT_TEMP) != 0) {
143*3448Sdh155122 		status = i_dladm_set_prop_temp(link, prop_name, prop_val,
144*3448Sdh155122 		    val_cnt, flags, errprop);
145*3448Sdh155122 		if (status == DLADM_STATUS_TEMPONLY &&
146*3448Sdh155122 		    (flags & DLADM_OPT_PERSIST) != 0)
147*3448Sdh155122 			return (DLADM_STATUS_TEMPONLY);
148*3448Sdh155122 
149*3448Sdh155122 		if (status == DLADM_STATUS_NOTFOUND) {
150*3448Sdh155122 			status = DLADM_STATUS_BADARG;
151*3448Sdh155122 			if (wladm_is_valid(link)) {
152*3448Sdh155122 				status = dladm_wladmstatus2status(
153*3448Sdh155122 				    wladm_set_prop(link, prop_name,
154*3448Sdh155122 				    prop_val, val_cnt, errprop));
155*3448Sdh155122 			}
1563147Sxc151355 		}
1573147Sxc151355 		if (status != DLADM_STATUS_OK)
1583147Sxc151355 			return (status);
1593147Sxc151355 	}
1603147Sxc151355 	if ((flags & DLADM_OPT_PERSIST) != 0) {
161*3448Sdh155122 		if (i_dladm_is_prop_temponly(prop_name, errprop))
162*3448Sdh155122 			return (DLADM_STATUS_TEMPONLY);
163*3448Sdh155122 
1643147Sxc151355 		status = i_dladm_set_prop_db(link, prop_name,
1653147Sxc151355 		    prop_val, val_cnt);
1663147Sxc151355 	}
1673147Sxc151355 	return (status);
1683147Sxc151355 }
1693147Sxc151355 
1703147Sxc151355 dladm_status_t
1713147Sxc151355 dladm_walk_prop(const char *link, void *arg,
1723147Sxc151355     boolean_t (*func)(void *, const char *))
1733147Sxc151355 {
174*3448Sdh155122 	int	i;
175*3448Sdh155122 
1763147Sxc151355 	if (link == NULL || func == NULL)
1773147Sxc151355 		return (DLADM_STATUS_BADARG);
1783147Sxc151355 
179*3448Sdh155122 	/* For wifi links, show wifi properties first */
1803147Sxc151355 	if (wladm_is_valid(link)) {
181*3448Sdh155122 		dladm_status_t	status;
182*3448Sdh155122 
183*3448Sdh155122 		status = dladm_wladmstatus2status(
184*3448Sdh155122 		    wladm_walk_prop(link, arg, func));
185*3448Sdh155122 		if (status != DLADM_STATUS_OK)
186*3448Sdh155122 			return (status);
1873147Sxc151355 	}
188*3448Sdh155122 
189*3448Sdh155122 	/* Then show data-link properties if there are any */
190*3448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
191*3448Sdh155122 		if (!func(arg, prop_table[i].pd_name))
192*3448Sdh155122 			break;
193*3448Sdh155122 	}
194*3448Sdh155122 	return (DLADM_STATUS_OK);
1953147Sxc151355 }
1963147Sxc151355 
1973147Sxc151355 dladm_status_t
1983147Sxc151355 dladm_get_prop(const char *link, dladm_prop_type_t type,
1993147Sxc151355     const char *prop_name, char **prop_val, uint_t *val_cntp)
2003147Sxc151355 {
201*3448Sdh155122 	dladm_status_t status;
202*3448Sdh155122 
2033147Sxc151355 	if (link == NULL || prop_name == NULL || prop_val == NULL ||
2043147Sxc151355 	    val_cntp == NULL || *val_cntp == 0)
2053147Sxc151355 		return (DLADM_STATUS_BADARG);
2063147Sxc151355 
2073147Sxc151355 	if (type == DLADM_PROP_VAL_PERSISTENT) {
2083147Sxc151355 		return (i_dladm_get_prop_db(link, prop_name,
2093147Sxc151355 		    prop_val, val_cntp));
2103147Sxc151355 	}
2113147Sxc151355 
212*3448Sdh155122 	status = i_dladm_get_prop_temp(link, type, prop_name,
213*3448Sdh155122 	    prop_val, val_cntp);
214*3448Sdh155122 	if (status != DLADM_STATUS_NOTFOUND)
215*3448Sdh155122 		return (status);
216*3448Sdh155122 
2173147Sxc151355 	if (wladm_is_valid(link)) {
2183147Sxc151355 		wladm_prop_type_t	wtype;
2193147Sxc151355 
2203147Sxc151355 		switch (type) {
2213147Sxc151355 		case DLADM_PROP_VAL_CURRENT:
2223147Sxc151355 			wtype = WLADM_PROP_VAL_CURRENT;
2233147Sxc151355 			break;
2243147Sxc151355 		case DLADM_PROP_VAL_DEFAULT:
2253147Sxc151355 			wtype = WLADM_PROP_VAL_DEFAULT;
2263147Sxc151355 			break;
2273147Sxc151355 		case DLADM_PROP_VAL_MODIFIABLE:
2283147Sxc151355 			wtype = WLADM_PROP_VAL_MODIFIABLE;
2293147Sxc151355 			break;
2303147Sxc151355 		default:
2313147Sxc151355 			return (DLADM_STATUS_BADARG);
2323147Sxc151355 		}
2333147Sxc151355 
2343147Sxc151355 		return (dladm_wladmstatus2status(
2353147Sxc151355 		    wladm_get_prop(link, wtype, prop_name,
2363147Sxc151355 		    prop_val, val_cntp)));
2373147Sxc151355 	}
2383147Sxc151355 	return (DLADM_STATUS_BADARG);
2393147Sxc151355 }
2403147Sxc151355 
2413147Sxc151355 /*
2423147Sxc151355  * Data structures used for implementing persistent link properties
2433147Sxc151355  */
2443147Sxc151355 typedef struct linkprop_val {
2453147Sxc151355 	const char		*lv_name;
2463147Sxc151355 	struct linkprop_val	*lv_nextval;
2473147Sxc151355 } linkprop_val_t;
2483147Sxc151355 
2493147Sxc151355 typedef struct linkprop_info {
2503147Sxc151355 	const char		*li_name;
2513147Sxc151355 	struct linkprop_info	*li_nextprop;
2523147Sxc151355 	struct linkprop_val	*li_val;
2533147Sxc151355 } linkprop_info_t;
2543147Sxc151355 
2553147Sxc151355 typedef struct linkprop_db_state	linkprop_db_state_t;
2563147Sxc151355 
2573147Sxc151355 typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *,
2583147Sxc151355     char *, linkprop_info_t *, dladm_status_t *);
2593147Sxc151355 
2603147Sxc151355 struct linkprop_db_state {
2613147Sxc151355 	linkprop_db_op_t	ls_op;
2623147Sxc151355 	const char		*ls_link;
2633147Sxc151355 	const char		*ls_propname;
2643147Sxc151355 	char			**ls_propval;
2653147Sxc151355 	uint_t			*ls_valcntp;
2663147Sxc151355 };
2673147Sxc151355 
2683147Sxc151355 static void
2693147Sxc151355 free_linkprops(linkprop_info_t *lip)
2703147Sxc151355 {
2713147Sxc151355 	linkprop_info_t	*lip_next;
2723147Sxc151355 	linkprop_val_t	*lvp, *lvp_next;
2733147Sxc151355 
2743147Sxc151355 	for (; lip != NULL; lip = lip_next) {
2753147Sxc151355 		lip_next = lip->li_nextprop;
2763147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
2773147Sxc151355 			lvp_next = lvp->lv_nextval;
2783147Sxc151355 			free(lvp);
2793147Sxc151355 		}
2803147Sxc151355 		free(lip);
2813147Sxc151355 	}
2823147Sxc151355 }
2833147Sxc151355 
2843147Sxc151355 /*
2853147Sxc151355  * Generate an entry in the link property database.
2863147Sxc151355  * Each entry has this format:
2873147Sxc151355  * <linkname>	<prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
2883147Sxc151355  */
2893147Sxc151355 static void
2903147Sxc151355 generate_linkprop_line(linkprop_db_state_t *lsp, char *buf,
2913147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
2923147Sxc151355 {
2933147Sxc151355 	char		tmpbuf[MAXLINELEN];
2943147Sxc151355 	char		*ptr, *lim = tmpbuf + MAXLINELEN;
2953147Sxc151355 	linkprop_info_t	*lip = listp;
2963147Sxc151355 	linkprop_val_t	*lvp = NULL;
2973147Sxc151355 
2983147Sxc151355 	/*
2993147Sxc151355 	 * Delete line if there are no properties left.
3003147Sxc151355 	 */
3013147Sxc151355 	if (lip == NULL ||
3023147Sxc151355 	    (lip->li_val == NULL && lip->li_nextprop == NULL)) {
3033147Sxc151355 		buf[0] = '\0';
3043147Sxc151355 		return;
3053147Sxc151355 	}
3063147Sxc151355 	ptr = tmpbuf;
3073147Sxc151355 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link);
3083147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
3093147Sxc151355 		/*
3103147Sxc151355 		 * Skip properties without values.
3113147Sxc151355 		 */
3123147Sxc151355 		if (lip->li_val == NULL)
3133147Sxc151355 			continue;
3143147Sxc151355 
3153147Sxc151355 		ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
3163147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
3173147Sxc151355 			ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
3183147Sxc151355 			    lvp->lv_name,
3193147Sxc151355 			    ((lvp->lv_nextval == NULL) ? ';' : ','));
3203147Sxc151355 		}
3213147Sxc151355 	}
3223147Sxc151355 	if (ptr > lim) {
3233147Sxc151355 		*statusp = DLADM_STATUS_TOOSMALL;
3243147Sxc151355 		return;
3253147Sxc151355 	}
3263147Sxc151355 	(void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
3273147Sxc151355 }
3283147Sxc151355 
3293147Sxc151355 /*
3303147Sxc151355  * This function is used to update or create an entry in the persistent db.
3313147Sxc151355  * process_linkprop_db() will first scan the db for an entry matching the
3323147Sxc151355  * specified link. If a match is found, this function is invoked with the
3333147Sxc151355  * entry's contents (buf) and its linked-list representation (listp). lsp
3343147Sxc151355  * holds the name and values of the property to be added or updated; this
3353147Sxc151355  * information will be merged with listp. Subsequently, an updated entry
3363147Sxc151355  * will be written to buf, which will in turn be written to disk by
3373147Sxc151355  * process_linkprop_db(). If no entry matches the specified link, listp
3383147Sxc151355  * will be NULL; a new entry will be generated in this case and it will
3393147Sxc151355  * contain only the property information in lsp.
3403147Sxc151355  */
3413147Sxc151355 static boolean_t
3423147Sxc151355 process_linkprop_set(linkprop_db_state_t *lsp, char *buf,
3433147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
3443147Sxc151355 {
3453147Sxc151355 	dladm_status_t	status;
3463147Sxc151355 	linkprop_info_t	*lastp = NULL, *lip = listp, *nlip = NULL;
3473147Sxc151355 	linkprop_val_t	**lvpp;
3483147Sxc151355 	int		i;
3493147Sxc151355 
3503147Sxc151355 	if (lsp->ls_propname == NULL) {
3513147Sxc151355 		buf[0] = '\0';
3523147Sxc151355 		return (B_FALSE);
3533147Sxc151355 	}
3543147Sxc151355 
3553147Sxc151355 	/*
3563147Sxc151355 	 * Find the linkprop we want to change.
3573147Sxc151355 	 */
3583147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
3593147Sxc151355 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
3603147Sxc151355 			break;
3613147Sxc151355 
3623147Sxc151355 		lastp = lip;
3633147Sxc151355 	}
3643147Sxc151355 
3653147Sxc151355 	if (lip == NULL) {
3663147Sxc151355 		/*
3673147Sxc151355 		 * If the linkprop is not found, append it to the list.
3683147Sxc151355 		 */
3693147Sxc151355 		if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) {
3703147Sxc151355 			status = DLADM_STATUS_NOMEM;
3713147Sxc151355 			goto fail;
3723147Sxc151355 		}
3733147Sxc151355 		/*
3743147Sxc151355 		 * nlip will need to be freed later if there is no list to
3753147Sxc151355 		 * append to.
3763147Sxc151355 		 */
3773147Sxc151355 		if (lastp != NULL)
3783147Sxc151355 			lastp->li_nextprop = nlip;
3793147Sxc151355 		nlip->li_name = lsp->ls_propname;
3803147Sxc151355 		nlip->li_nextprop = NULL;
3813147Sxc151355 		nlip->li_val = NULL;
3823147Sxc151355 		lvpp = &nlip->li_val;
3833147Sxc151355 	} else {
3843147Sxc151355 		linkprop_val_t	*lvp, *lvp_next;
3853147Sxc151355 
3863147Sxc151355 		/*
3873147Sxc151355 		 * If the linkprop is found, delete the existing values from it.
3883147Sxc151355 		 */
3893147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
3903147Sxc151355 			lvp_next = lvp->lv_nextval;
3913147Sxc151355 			free(lvp);
3923147Sxc151355 		}
3933147Sxc151355 		lip->li_val = NULL;
3943147Sxc151355 		lvpp = &lip->li_val;
3953147Sxc151355 	}
3963147Sxc151355 
3973147Sxc151355 	/*
3983147Sxc151355 	 * Fill our linkprop with the specified values.
3993147Sxc151355 	 */
4003147Sxc151355 	for (i = 0; i < *lsp->ls_valcntp; i++) {
4013147Sxc151355 		if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) {
4023147Sxc151355 			status = DLADM_STATUS_NOMEM;
4033147Sxc151355 			goto fail;
4043147Sxc151355 		}
4053147Sxc151355 		(*lvpp)->lv_name = lsp->ls_propval[i];
4063147Sxc151355 		(*lvpp)->lv_nextval = NULL;
4073147Sxc151355 		lvpp = &(*lvpp)->lv_nextval;
4083147Sxc151355 	}
4093147Sxc151355 
4103147Sxc151355 	if (listp != NULL) {
4113147Sxc151355 		generate_linkprop_line(lsp, buf, listp, statusp);
4123147Sxc151355 	} else {
4133147Sxc151355 		generate_linkprop_line(lsp, buf, nlip, statusp);
4143147Sxc151355 		free_linkprops(nlip);
4153147Sxc151355 	}
4163147Sxc151355 	return (B_FALSE);
4173147Sxc151355 
4183147Sxc151355 fail:
4193147Sxc151355 	*statusp = status;
4203147Sxc151355 	if (listp == NULL)
4213147Sxc151355 		free_linkprops(nlip);
4223147Sxc151355 
4233147Sxc151355 	return (B_FALSE);
4243147Sxc151355 }
4253147Sxc151355 
4263147Sxc151355 /*
4273147Sxc151355  * This function is used for retrieving the values for a specific property.
4283147Sxc151355  * It gets called if an entry matching the specified link exists in the db.
4293147Sxc151355  * The entry is converted into a linked-list listp. This list is then scanned
4303147Sxc151355  * for the specified property name; if a matching property exists, its
4313147Sxc151355  * associated values are copied to the array lsp->ls_propval.
4323147Sxc151355  */
4333147Sxc151355 /* ARGSUSED */
4343147Sxc151355 static boolean_t
4353147Sxc151355 process_linkprop_get(linkprop_db_state_t *lsp, char *buf,
4363147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
4373147Sxc151355 {
4383147Sxc151355 	linkprop_info_t	*lip = listp;
4393147Sxc151355 	linkprop_val_t	*lvp;
4403147Sxc151355 	uint_t		valcnt = 0;
4413147Sxc151355 
4423147Sxc151355 	/*
4433147Sxc151355 	 * Find the linkprop we want to get.
4443147Sxc151355 	 */
4453147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
4463147Sxc151355 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
4473147Sxc151355 			break;
4483147Sxc151355 	}
4493147Sxc151355 	if (lip == NULL) {
4503147Sxc151355 		*statusp = DLADM_STATUS_NOTFOUND;
4513147Sxc151355 		return (B_FALSE);
4523147Sxc151355 	}
4533147Sxc151355 
4543147Sxc151355 	for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
4553147Sxc151355 		(void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
4563147Sxc151355 		    DLADM_PROP_VAL_MAX);
4573147Sxc151355 
4583147Sxc151355 		if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
4593147Sxc151355 			*statusp = DLADM_STATUS_TOOSMALL;
4603147Sxc151355 			return (B_FALSE);
4613147Sxc151355 		}
4623147Sxc151355 	}
4633147Sxc151355 	/*
4643147Sxc151355 	 * This function is meant to be called at most once for each call
4653147Sxc151355 	 * to process_linkprop_db(). For this reason, it's ok to overwrite
4663147Sxc151355 	 * the caller's valcnt array size with the actual number of values
4673147Sxc151355 	 * returned.
4683147Sxc151355 	 */
4693147Sxc151355 	*lsp->ls_valcntp = valcnt;
4703147Sxc151355 	return (B_FALSE);
4713147Sxc151355 }
4723147Sxc151355 
4733147Sxc151355 /*
4743147Sxc151355  * This is used for initializing link properties.
4753147Sxc151355  * Unlike the other routines, this gets called for every entry in the
4763147Sxc151355  * database. lsp->ls_link is not user-specified but instead is set to
4773147Sxc151355  * the current link being processed.
4783147Sxc151355  */
4793147Sxc151355 /* ARGSUSED */
4803147Sxc151355 static boolean_t
4813147Sxc151355 process_linkprop_init(linkprop_db_state_t *lsp, char *buf,
4823147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
4833147Sxc151355 {
4843147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
4853147Sxc151355 	linkprop_info_t	*lip = listp;
4863147Sxc151355 	linkprop_val_t	*lvp;
4873147Sxc151355 	uint_t		valcnt, i;
4883147Sxc151355 	char		**propval;
4893147Sxc151355 
4903147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
4913147Sxc151355 		/*
4923147Sxc151355 		 * Construct the propval array and fill it with
4933147Sxc151355 		 * values from listp.
4943147Sxc151355 		 */
4953147Sxc151355 		for (lvp = lip->li_val, valcnt = 0;
4963147Sxc151355 		    lvp != NULL; lvp = lvp->lv_nextval, valcnt++);
4973147Sxc151355 
4983147Sxc151355 		propval = malloc(sizeof (char *) * valcnt);
4993147Sxc151355 		if (propval == NULL) {
5003147Sxc151355 			*statusp = DLADM_STATUS_NOMEM;
5013147Sxc151355 			break;
5023147Sxc151355 		}
5033147Sxc151355 		lvp = lip->li_val;
5043147Sxc151355 		for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
5053147Sxc151355 			propval[i] = (char *)lvp->lv_name;
5063147Sxc151355 
5073147Sxc151355 		status = dladm_set_prop(lsp->ls_link, lip->li_name,
508*3448Sdh155122 		    propval, valcnt, DLADM_OPT_TEMP, NULL);
5093147Sxc151355 
5103147Sxc151355 		/*
5113147Sxc151355 		 * We continue with initializing other properties even
5123147Sxc151355 		 * after encountering an error. This error will be
5133147Sxc151355 		 * propagated to the caller via 'statusp'.
5143147Sxc151355 		 */
5153147Sxc151355 		if (status != DLADM_STATUS_OK)
5163147Sxc151355 			*statusp = status;
5173147Sxc151355 
5183147Sxc151355 		free(propval);
5193147Sxc151355 	}
5203147Sxc151355 	return (B_TRUE);
5213147Sxc151355 }
5223147Sxc151355 
5233147Sxc151355 static int
5243147Sxc151355 parse_linkprops(char *buf, linkprop_info_t **lipp)
5253147Sxc151355 {
5263147Sxc151355 	int			i, len;
5273147Sxc151355 	char			*curr;
5283147Sxc151355 	linkprop_info_t		*lip = NULL;
5293147Sxc151355 	linkprop_info_t		**tailp = lipp;
5303147Sxc151355 	linkprop_val_t		*lvp = NULL;
5313147Sxc151355 	linkprop_val_t		**vtailp = NULL;
5323147Sxc151355 
5333147Sxc151355 	curr = buf;
5343147Sxc151355 	len = strlen(buf);
5353147Sxc151355 	for (i = 0; i < len; i++) {
5363147Sxc151355 		char		c = buf[i];
5373147Sxc151355 		boolean_t	match = (c == '=' || c == ',' || c == ';');
5383147Sxc151355 
5393147Sxc151355 		/*
5403147Sxc151355 		 * Move to the next character if there is no match and
5413147Sxc151355 		 * if we have not reached the last character.
5423147Sxc151355 		 */
5433147Sxc151355 		if (!match && i != len - 1)
5443147Sxc151355 			continue;
5453147Sxc151355 
5463147Sxc151355 		if (match) {
5473147Sxc151355 			/*
5483147Sxc151355 			 * Nul-terminate the string pointed to by 'curr'.
5493147Sxc151355 			 */
5503147Sxc151355 			buf[i] = '\0';
5513147Sxc151355 			if (*curr == '\0')
5523147Sxc151355 				goto fail;
5533147Sxc151355 		}
5543147Sxc151355 
5553147Sxc151355 		if (lip != NULL) {
5563147Sxc151355 			/*
5573147Sxc151355 			 * We get here after we have processed the "<prop>="
5583147Sxc151355 			 * pattern. The pattern we are now interested in is
5593147Sxc151355 			 * "<val0>,<val1>,...,<valn>;". For each value we
5603147Sxc151355 			 * find, a linkprop_val_t will be allocated and
5613147Sxc151355 			 * added to the current 'lip'.
5623147Sxc151355 			 */
5633147Sxc151355 			if (c == '=')
5643147Sxc151355 				goto fail;
5653147Sxc151355 
5663147Sxc151355 			lvp = malloc(sizeof (*lvp));
5673147Sxc151355 			if (lvp == NULL)
5683147Sxc151355 				goto fail;
5693147Sxc151355 
5703147Sxc151355 			lvp->lv_name = curr;
5713147Sxc151355 			lvp->lv_nextval = NULL;
5723147Sxc151355 			*vtailp = lvp;
5733147Sxc151355 			vtailp = &lvp->lv_nextval;
5743147Sxc151355 
5753147Sxc151355 			if (c == ';') {
5763147Sxc151355 				tailp = &lip->li_nextprop;
5773147Sxc151355 				vtailp = NULL;
5783147Sxc151355 				lip = NULL;
5793147Sxc151355 			}
5803147Sxc151355 		} else {
5813147Sxc151355 			/*
5823147Sxc151355 			 * lip == NULL indicates that 'curr' must be refering
5833147Sxc151355 			 * to a property name. We allocate a new linkprop_info_t
5843147Sxc151355 			 * append it to the list given by the caller.
5853147Sxc151355 			 */
5863147Sxc151355 			if (c != '=')
5873147Sxc151355 				goto fail;
5883147Sxc151355 
5893147Sxc151355 			lip = malloc(sizeof (*lip));
5903147Sxc151355 			if (lip == NULL)
5913147Sxc151355 				goto fail;
5923147Sxc151355 
5933147Sxc151355 			lip->li_name = curr;
5943147Sxc151355 			lip->li_val = NULL;
5953147Sxc151355 			lip->li_nextprop = NULL;
5963147Sxc151355 			*tailp = lip;
5973147Sxc151355 			vtailp = &lip->li_val;
5983147Sxc151355 		}
5993147Sxc151355 		curr = buf + i + 1;
6003147Sxc151355 	}
6013147Sxc151355 	/*
6023147Sxc151355 	 * The list must be non-empty and the last character must be ';'.
6033147Sxc151355 	 */
6043147Sxc151355 	if (*lipp == NULL || lip != NULL)
6053147Sxc151355 		goto fail;
6063147Sxc151355 
6073147Sxc151355 	return (0);
6083147Sxc151355 
6093147Sxc151355 fail:
6103147Sxc151355 	free_linkprops(*lipp);
6113147Sxc151355 	*lipp = NULL;
6123147Sxc151355 	return (-1);
6133147Sxc151355 }
6143147Sxc151355 
6153147Sxc151355 static boolean_t
6163147Sxc151355 process_linkprop_line(linkprop_db_state_t *lsp, char *buf,
6173147Sxc151355     dladm_status_t *statusp)
6183147Sxc151355 {
6193147Sxc151355 	linkprop_info_t		*lip = NULL;
6203147Sxc151355 	int			i, len, llen;
6213147Sxc151355 	char			*str, *lasts;
6223147Sxc151355 	boolean_t		cont, nolink = B_FALSE;
6233147Sxc151355 
6243147Sxc151355 	/*
6253147Sxc151355 	 * Skip leading spaces, blank lines, and comments.
6263147Sxc151355 	 */
6273147Sxc151355 	len = strlen(buf);
6283147Sxc151355 	for (i = 0; i < len; i++) {
6293147Sxc151355 		if (!isspace(buf[i]))
6303147Sxc151355 			break;
6313147Sxc151355 	}
6323147Sxc151355 	if (i == len || buf[i] == '#')
6333147Sxc151355 		return (B_TRUE);
6343147Sxc151355 
6353147Sxc151355 	str = buf + i;
6363147Sxc151355 	if (lsp->ls_link != NULL) {
6373147Sxc151355 		/*
6383147Sxc151355 		 * Skip links we're not interested in.
6393147Sxc151355 		 * Note that strncmp() and isspace() are used here
6403147Sxc151355 		 * instead of strtok() and strcmp() because we don't
6413147Sxc151355 		 * want to modify buf in case it does not contain the
6423147Sxc151355 		 * specified link.
6433147Sxc151355 		 */
6443147Sxc151355 		llen = strlen(lsp->ls_link);
6453147Sxc151355 		if (strncmp(str, lsp->ls_link, llen) != 0 ||
6463147Sxc151355 		    !isspace(str[llen]))
6473147Sxc151355 			return (B_TRUE);
6483147Sxc151355 	} else {
6493147Sxc151355 		/*
6503147Sxc151355 		 * If a link is not specified, find the link name
6513147Sxc151355 		 * and assign it to lsp->ls_link.
6523147Sxc151355 		 */
6533147Sxc151355 		if (strtok_r(str, " \n\t", &lasts) == NULL)
6543147Sxc151355 			goto fail;
6553147Sxc151355 
6563147Sxc151355 		llen = strlen(str);
6573147Sxc151355 		lsp->ls_link = str;
6583147Sxc151355 		nolink = B_TRUE;
6593147Sxc151355 	}
6603147Sxc151355 	str += llen + 1;
6613147Sxc151355 	if (str >= buf + len)
6623147Sxc151355 		goto fail;
6633147Sxc151355 
6643147Sxc151355 	/*
6653147Sxc151355 	 * Now find the list of link properties.
6663147Sxc151355 	 */
6673147Sxc151355 	if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
6683147Sxc151355 		goto fail;
6693147Sxc151355 
6703147Sxc151355 	if (parse_linkprops(str, &lip) < 0)
6713147Sxc151355 		goto fail;
6723147Sxc151355 
6733147Sxc151355 	cont = (*lsp->ls_op)(lsp, buf, lip, statusp);
6743147Sxc151355 	free_linkprops(lip);
6753147Sxc151355 	if (nolink)
6763147Sxc151355 		lsp->ls_link = NULL;
6773147Sxc151355 	return (cont);
6783147Sxc151355 
6793147Sxc151355 fail:
6803147Sxc151355 	free_linkprops(lip);
6813147Sxc151355 	if (nolink)
6823147Sxc151355 		lsp->ls_link = NULL;
6833147Sxc151355 
6843147Sxc151355 	/*
6853147Sxc151355 	 * Delete corrupted line.
6863147Sxc151355 	 */
6873147Sxc151355 	buf[0] = '\0';
6883147Sxc151355 	return (B_TRUE);
6893147Sxc151355 }
6903147Sxc151355 
6913147Sxc151355 static dladm_status_t
6923147Sxc151355 process_linkprop_db(void *arg, FILE *fp, FILE *nfp)
6933147Sxc151355 {
6943147Sxc151355 	linkprop_db_state_t	*lsp = arg;
6953147Sxc151355 	dladm_status_t		status = DLADM_STATUS_OK;
6963147Sxc151355 	char			buf[MAXLINELEN];
6973147Sxc151355 	boolean_t		cont = B_TRUE;
6983147Sxc151355 
6993147Sxc151355 	/*
7003147Sxc151355 	 * This loop processes each line of the configuration file.
7013147Sxc151355 	 * buf can potentially be modified by process_linkprop_line().
7023147Sxc151355 	 * If this is a write operation and buf is not truncated, buf will
7033147Sxc151355 	 * be written to disk. process_linkprop_line() will no longer be
7043147Sxc151355 	 * called after it returns B_FALSE; at which point the remainder
7053147Sxc151355 	 * of the file will continue to be read and, if necessary, written
7063147Sxc151355 	 * to disk as well.
7073147Sxc151355 	 */
7083147Sxc151355 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
7093147Sxc151355 		if (cont)
7103147Sxc151355 			cont = process_linkprop_line(lsp, buf, &status);
7113147Sxc151355 
7123147Sxc151355 		if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
7133147Sxc151355 			status = dladm_errno2status(errno);
7143147Sxc151355 			break;
7153147Sxc151355 		}
7163147Sxc151355 	}
7173147Sxc151355 
7183147Sxc151355 	if (status != DLADM_STATUS_OK || !cont)
7193147Sxc151355 		return (status);
7203147Sxc151355 
7213147Sxc151355 	if (lsp->ls_op == process_linkprop_set) {
7223147Sxc151355 		/*
7233147Sxc151355 		 * If the specified link is not found above, we add the
7243147Sxc151355 		 * link and its properties to the configuration file.
7253147Sxc151355 		 */
7263147Sxc151355 		(void) (*lsp->ls_op)(lsp, buf, NULL, &status);
7273147Sxc151355 		if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
7283147Sxc151355 			status = dladm_errno2status(errno);
7293147Sxc151355 	}
7303147Sxc151355 
7313147Sxc151355 	if (lsp->ls_op == process_linkprop_get)
7323147Sxc151355 		status = DLADM_STATUS_NOTFOUND;
7333147Sxc151355 
7343147Sxc151355 	return (status);
7353147Sxc151355 }
7363147Sxc151355 
7373147Sxc151355 #define	LINKPROP_RW_DB(statep, writeop) \
7383147Sxc151355 	(i_dladm_rw_db("/etc/dladm/linkprop.conf", \
7393147Sxc151355 	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \
7403147Sxc151355 	(statep), (writeop)))
7413147Sxc151355 
7423147Sxc151355 static dladm_status_t
7433147Sxc151355 i_dladm_set_prop_db(const char *link, const char *prop_name,
7443147Sxc151355     char **prop_val, uint_t val_cnt)
7453147Sxc151355 {
7463147Sxc151355 	linkprop_db_state_t	state;
7473147Sxc151355 
7483147Sxc151355 	state.ls_op = process_linkprop_set;
7493147Sxc151355 	state.ls_link = link;
7503147Sxc151355 	state.ls_propname = prop_name;
7513147Sxc151355 	state.ls_propval = prop_val;
7523147Sxc151355 	state.ls_valcntp = &val_cnt;
7533147Sxc151355 
7543147Sxc151355 	return (LINKPROP_RW_DB(&state, B_TRUE));
7553147Sxc151355 }
7563147Sxc151355 
7573147Sxc151355 static dladm_status_t
7583147Sxc151355 i_dladm_get_prop_db(const char *link, const char *prop_name,
7593147Sxc151355     char **prop_val, uint_t *val_cntp)
7603147Sxc151355 {
7613147Sxc151355 	linkprop_db_state_t	state;
7623147Sxc151355 
7633147Sxc151355 	state.ls_op = process_linkprop_get;
7643147Sxc151355 	state.ls_link = link;
7653147Sxc151355 	state.ls_propname = prop_name;
7663147Sxc151355 	state.ls_propval = prop_val;
7673147Sxc151355 	state.ls_valcntp = val_cntp;
7683147Sxc151355 
7693147Sxc151355 	return (LINKPROP_RW_DB(&state, B_FALSE));
7703147Sxc151355 }
7713147Sxc151355 
7723147Sxc151355 dladm_status_t
7733147Sxc151355 dladm_init_linkprop(void)
7743147Sxc151355 {
7753147Sxc151355 	linkprop_db_state_t	state;
7763147Sxc151355 
7773147Sxc151355 	state.ls_op = process_linkprop_init;
7783147Sxc151355 	state.ls_link = NULL;
7793147Sxc151355 	state.ls_propname = NULL;
7803147Sxc151355 	state.ls_propval = NULL;
7813147Sxc151355 	state.ls_valcntp = NULL;
7823147Sxc151355 
7833147Sxc151355 	return (LINKPROP_RW_DB(&state, B_FALSE));
7843147Sxc151355 }
785*3448Sdh155122 
786*3448Sdh155122 static dladm_status_t
787*3448Sdh155122 i_dladm_get_zoneid(const char *link, zoneid_t *zidp)
788*3448Sdh155122 {
789*3448Sdh155122 	int fd;
790*3448Sdh155122 	dld_hold_vlan_t	dhv;
791*3448Sdh155122 
792*3448Sdh155122 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
793*3448Sdh155122 		return (dladm_errno2status(errno));
794*3448Sdh155122 
795*3448Sdh155122 	bzero(&dhv, sizeof (dld_hold_vlan_t));
796*3448Sdh155122 	(void) strlcpy(dhv.dhv_name, link, IFNAMSIZ);
797*3448Sdh155122 	dhv.dhv_zid = -1;
798*3448Sdh155122 
799*3448Sdh155122 	if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0 &&
800*3448Sdh155122 	    errno != ENOENT) {
801*3448Sdh155122 		dladm_status_t status = dladm_errno2status(errno);
802*3448Sdh155122 
803*3448Sdh155122 		(void) close(fd);
804*3448Sdh155122 		return (status);
805*3448Sdh155122 	}
806*3448Sdh155122 
807*3448Sdh155122 	if (errno == ENOENT)
808*3448Sdh155122 		*zidp = GLOBAL_ZONEID;
809*3448Sdh155122 	else
810*3448Sdh155122 		*zidp = dhv.dhv_zid;
811*3448Sdh155122 
812*3448Sdh155122 	(void) close(fd);
813*3448Sdh155122 	return (DLADM_STATUS_OK);
814*3448Sdh155122 }
815*3448Sdh155122 
816*3448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
817*3448Sdh155122 
818*3448Sdh155122 static int
819*3448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
820*3448Sdh155122 {
821*3448Sdh155122 	char			root[MAXPATHLEN];
822*3448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
823*3448Sdh155122 	void			*dlhandle;
824*3448Sdh155122 	void			*sym;
825*3448Sdh155122 	int			ret;
826*3448Sdh155122 
827*3448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
828*3448Sdh155122 		return (-1);
829*3448Sdh155122 
830*3448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
831*3448Sdh155122 		(void) dlclose(dlhandle);
832*3448Sdh155122 		return (-1);
833*3448Sdh155122 	}
834*3448Sdh155122 
835*3448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
836*3448Sdh155122 
837*3448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
838*3448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
839*3448Sdh155122 	(void) dlclose(dlhandle);
840*3448Sdh155122 	return (ret);
841*3448Sdh155122 }
842*3448Sdh155122 
843*3448Sdh155122 static dladm_status_t
844*3448Sdh155122 i_dladm_add_deventry(zoneid_t zid, const char *link)
845*3448Sdh155122 {
846*3448Sdh155122 	char		path[MAXPATHLEN];
847*3448Sdh155122 	di_prof_t	prof = NULL;
848*3448Sdh155122 	char		zone_name[ZONENAME_MAX];
849*3448Sdh155122 	dladm_status_t	status;
850*3448Sdh155122 
851*3448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
852*3448Sdh155122 		return (dladm_errno2status(errno));
853*3448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
854*3448Sdh155122 		return (dladm_errno2status(errno));
855*3448Sdh155122 	if (di_prof_init(path, &prof) != 0)
856*3448Sdh155122 		return (dladm_errno2status(errno));
857*3448Sdh155122 
858*3448Sdh155122 	status = DLADM_STATUS_OK;
859*3448Sdh155122 	if (di_prof_add_dev(prof, link) != 0) {
860*3448Sdh155122 		status = dladm_errno2status(errno);
861*3448Sdh155122 		goto cleanup;
862*3448Sdh155122 	}
863*3448Sdh155122 	if (di_prof_commit(prof) != 0)
864*3448Sdh155122 		status = dladm_errno2status(errno);
865*3448Sdh155122 cleanup:
866*3448Sdh155122 	if (prof)
867*3448Sdh155122 		di_prof_fini(prof);
868*3448Sdh155122 
869*3448Sdh155122 	return (status);
870*3448Sdh155122 }
871*3448Sdh155122 
872*3448Sdh155122 static dladm_status_t
873*3448Sdh155122 i_dladm_remove_deventry(zoneid_t zid, const char *link)
874*3448Sdh155122 {
875*3448Sdh155122 	char		path[MAXPATHLEN];
876*3448Sdh155122 	di_prof_t	prof = NULL;
877*3448Sdh155122 	char		zone_name[ZONENAME_MAX];
878*3448Sdh155122 	dladm_status_t	status;
879*3448Sdh155122 
880*3448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
881*3448Sdh155122 		return (dladm_errno2status(errno));
882*3448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
883*3448Sdh155122 		return (dladm_errno2status(errno));
884*3448Sdh155122 	if (di_prof_init(path, &prof) != 0)
885*3448Sdh155122 		return (dladm_errno2status(errno));
886*3448Sdh155122 
887*3448Sdh155122 	status = DLADM_STATUS_OK;
888*3448Sdh155122 	if (di_prof_add_exclude(prof, link) != 0) {
889*3448Sdh155122 		status = dladm_errno2status(errno);
890*3448Sdh155122 		goto cleanup;
891*3448Sdh155122 	}
892*3448Sdh155122 	if (di_prof_commit(prof) != 0)
893*3448Sdh155122 		status = dladm_errno2status(errno);
894*3448Sdh155122 cleanup:
895*3448Sdh155122 	if (prof)
896*3448Sdh155122 		di_prof_fini(prof);
897*3448Sdh155122 
898*3448Sdh155122 	return (status);
899*3448Sdh155122 }
900*3448Sdh155122 
901*3448Sdh155122 static dladm_status_t
902*3448Sdh155122 do_get_zone(const char *link, char **prop_val, uint_t *val_cnt)
903*3448Sdh155122 {
904*3448Sdh155122 	char		zone_name[ZONENAME_MAX];
905*3448Sdh155122 	zoneid_t	zid;
906*3448Sdh155122 	dladm_status_t	status;
907*3448Sdh155122 
908*3448Sdh155122 	status = i_dladm_get_zoneid(link, &zid);
909*3448Sdh155122 	if (status != DLADM_STATUS_OK)
910*3448Sdh155122 		return (status);
911*3448Sdh155122 
912*3448Sdh155122 	*val_cnt = 1;
913*3448Sdh155122 	if (zid != GLOBAL_ZONEID) {
914*3448Sdh155122 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
915*3448Sdh155122 			return (dladm_errno2status(errno));
916*3448Sdh155122 
917*3448Sdh155122 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
918*3448Sdh155122 	} else {
919*3448Sdh155122 		*prop_val[0] = '\0';
920*3448Sdh155122 	}
921*3448Sdh155122 
922*3448Sdh155122 	return (DLADM_STATUS_OK);
923*3448Sdh155122 }
924*3448Sdh155122 
925*3448Sdh155122 static dladm_status_t
926*3448Sdh155122 do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt)
927*3448Sdh155122 {
928*3448Sdh155122 	dladm_status_t	status;
929*3448Sdh155122 	zoneid_t	zid_old, zid_new;
930*3448Sdh155122 	char		buff[IF_NAMESIZE + 1];
931*3448Sdh155122 	struct stat	st;
932*3448Sdh155122 
933*3448Sdh155122 	if (val_cnt != 1)
934*3448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
935*3448Sdh155122 
936*3448Sdh155122 	status = i_dladm_get_zoneid(link, &zid_old);
937*3448Sdh155122 	if (status != DLADM_STATUS_OK)
938*3448Sdh155122 		return (status);
939*3448Sdh155122 
940*3448Sdh155122 	/* Do nothing if setting to current value */
941*3448Sdh155122 	zid_new = (zoneid_t)vdp->vd_val;
942*3448Sdh155122 	if (zid_new == zid_old)
943*3448Sdh155122 		return (DLADM_STATUS_OK);
944*3448Sdh155122 
945*3448Sdh155122 	/* Do a stat to get the vlan created by MAC, if it's not there */
946*3448Sdh155122 	(void) strcpy(buff, "/dev/");
947*3448Sdh155122 	(void) strlcat(buff, link, IF_NAMESIZE);
948*3448Sdh155122 	(void) stat(buff, &st);
949*3448Sdh155122 
950*3448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
951*3448Sdh155122 		if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0)
952*3448Sdh155122 			return (dladm_errno2status(errno));
953*3448Sdh155122 
954*3448Sdh155122 		if (zone_remove_datalink(zid_old, (char *)link) != 0 &&
955*3448Sdh155122 		    errno != ENXIO) {
956*3448Sdh155122 			status = dladm_errno2status(errno);
957*3448Sdh155122 			goto rollback1;
958*3448Sdh155122 		}
959*3448Sdh155122 
960*3448Sdh155122 		status = i_dladm_remove_deventry(zid_old, link);
961*3448Sdh155122 		if (status != DLADM_STATUS_OK)
962*3448Sdh155122 			goto rollback2;
963*3448Sdh155122 	}
964*3448Sdh155122 
965*3448Sdh155122 	if (zid_new != GLOBAL_ZONEID) {
966*3448Sdh155122 		if (zone_add_datalink(zid_new, (char *)link) != 0) {
967*3448Sdh155122 			status = dladm_errno2status(errno);
968*3448Sdh155122 			goto rollback3;
969*3448Sdh155122 		}
970*3448Sdh155122 
971*3448Sdh155122 		if (dladm_hold_link(link, zid_new, B_TRUE) < 0) {
972*3448Sdh155122 			(void) zone_remove_datalink(zid_new, (char *)link);
973*3448Sdh155122 			status = dladm_errno2status(errno);
974*3448Sdh155122 			goto rollback3;
975*3448Sdh155122 		}
976*3448Sdh155122 
977*3448Sdh155122 		status = i_dladm_add_deventry(zid_new, link);
978*3448Sdh155122 		if (status != DLADM_STATUS_OK) {
979*3448Sdh155122 			(void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE);
980*3448Sdh155122 			(void) zone_remove_datalink(zid_new, (char *)link);
981*3448Sdh155122 			goto rollback3;
982*3448Sdh155122 		}
983*3448Sdh155122 	}
984*3448Sdh155122 	return (DLADM_STATUS_OK);
985*3448Sdh155122 
986*3448Sdh155122 rollback3:
987*3448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
988*3448Sdh155122 		(void) i_dladm_add_deventry(zid_old, link);
989*3448Sdh155122 rollback2:
990*3448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
991*3448Sdh155122 		(void) zone_add_datalink(zid_old, (char *)link);
992*3448Sdh155122 rollback1:
993*3448Sdh155122 	(void) dladm_hold_link(link, zid_old, B_FALSE);
994*3448Sdh155122 cleanexit:
995*3448Sdh155122 	return (status);
996*3448Sdh155122 }
997*3448Sdh155122 
998*3448Sdh155122 /* ARGSUSED */
999*3448Sdh155122 static dladm_status_t
1000*3448Sdh155122 do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
1001*3448Sdh155122     val_desc_t **vdpp)
1002*3448Sdh155122 {
1003*3448Sdh155122 	zoneid_t 	zid;
1004*3448Sdh155122 	val_desc_t	*vdp = NULL;
1005*3448Sdh155122 
1006*3448Sdh155122 	if (val_cnt != 1)
1007*3448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
1008*3448Sdh155122 
1009*3448Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
1010*3448Sdh155122 		return (DLADM_STATUS_BADVAL);
1011*3448Sdh155122 
1012*3448Sdh155122 	if (zid != GLOBAL_ZONEID) {
1013*3448Sdh155122 		ushort_t	flags;
1014*3448Sdh155122 
1015*3448Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
1016*3448Sdh155122 		    sizeof (flags)) < 0) {
1017*3448Sdh155122 			return (dladm_errno2status(errno));
1018*3448Sdh155122 		}
1019*3448Sdh155122 
1020*3448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
1021*3448Sdh155122 			return (DLADM_STATUS_BADVAL);
1022*3448Sdh155122 		}
1023*3448Sdh155122 	}
1024*3448Sdh155122 
1025*3448Sdh155122 	vdp = malloc(sizeof (val_desc_t));
1026*3448Sdh155122 	if (vdp == NULL)
1027*3448Sdh155122 		return (DLADM_STATUS_NOMEM);
1028*3448Sdh155122 
1029*3448Sdh155122 	vdp->vd_val = (void *)zid;
1030*3448Sdh155122 	*vdpp = vdp;
1031*3448Sdh155122 	return (DLADM_STATUS_OK);
1032*3448Sdh155122 }
1033*3448Sdh155122 
1034*3448Sdh155122 static dladm_status_t
1035*3448Sdh155122 i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type,
1036*3448Sdh155122     const char *prop_name, char **prop_val, uint_t *val_cntp)
1037*3448Sdh155122 {
1038*3448Sdh155122 	int 		i;
1039*3448Sdh155122 	dladm_status_t	status;
1040*3448Sdh155122 	uint_t		cnt;
1041*3448Sdh155122 	prop_desc_t	*pdp;
1042*3448Sdh155122 
1043*3448Sdh155122 	if (link == NULL || prop_name == NULL || prop_val == NULL ||
1044*3448Sdh155122 	    val_cntp == NULL || *val_cntp == 0)
1045*3448Sdh155122 		return (DLADM_STATUS_BADARG);
1046*3448Sdh155122 
1047*3448Sdh155122 	for (i = 0; i < MAX_PROPS; i++)
1048*3448Sdh155122 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
1049*3448Sdh155122 			break;
1050*3448Sdh155122 
1051*3448Sdh155122 	if (i == MAX_PROPS)
1052*3448Sdh155122 		return (DLADM_STATUS_NOTFOUND);
1053*3448Sdh155122 
1054*3448Sdh155122 	pdp = &prop_table[i];
1055*3448Sdh155122 	status = DLADM_STATUS_OK;
1056*3448Sdh155122 
1057*3448Sdh155122 	switch (type) {
1058*3448Sdh155122 	case DLADM_PROP_VAL_CURRENT:
1059*3448Sdh155122 		status = pdp->pd_get(link, prop_val, val_cntp);
1060*3448Sdh155122 		break;
1061*3448Sdh155122 	case DLADM_PROP_VAL_DEFAULT:
1062*3448Sdh155122 		if (pdp->pd_defval.vd_name == NULL) {
1063*3448Sdh155122 			status = DLADM_STATUS_NOTSUP;
1064*3448Sdh155122 			break;
1065*3448Sdh155122 		}
1066*3448Sdh155122 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
1067*3448Sdh155122 		*val_cntp = 1;
1068*3448Sdh155122 		break;
1069*3448Sdh155122 
1070*3448Sdh155122 	case DLADM_PROP_VAL_MODIFIABLE:
1071*3448Sdh155122 		if (pdp->pd_getmod != NULL) {
1072*3448Sdh155122 			status = pdp->pd_getmod(link, prop_val, val_cntp);
1073*3448Sdh155122 			break;
1074*3448Sdh155122 		}
1075*3448Sdh155122 		cnt = pdp->pd_nmodval;
1076*3448Sdh155122 		if (cnt == 0) {
1077*3448Sdh155122 			status = DLADM_STATUS_NOTSUP;
1078*3448Sdh155122 		} else if (cnt > *val_cntp) {
1079*3448Sdh155122 			status = DLADM_STATUS_TOOSMALL;
1080*3448Sdh155122 		} else {
1081*3448Sdh155122 			for (i = 0; i < cnt; i++) {
1082*3448Sdh155122 				(void) strcpy(prop_val[i],
1083*3448Sdh155122 				    pdp->pd_modval[i].vd_name);
1084*3448Sdh155122 			}
1085*3448Sdh155122 			*val_cntp = cnt;
1086*3448Sdh155122 		}
1087*3448Sdh155122 		break;
1088*3448Sdh155122 	default:
1089*3448Sdh155122 		status = DLADM_STATUS_BADARG;
1090*3448Sdh155122 		break;
1091*3448Sdh155122 	}
1092*3448Sdh155122 
1093*3448Sdh155122 	return (status);
1094*3448Sdh155122 }
1095*3448Sdh155122 
1096*3448Sdh155122 static dladm_status_t
1097*3448Sdh155122 i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val,
1098*3448Sdh155122     uint_t val_cnt, uint_t flags)
1099*3448Sdh155122 {
1100*3448Sdh155122 	dladm_status_t	status;
1101*3448Sdh155122 	val_desc_t	*vdp = NULL;
1102*3448Sdh155122 	uint_t		cnt;
1103*3448Sdh155122 
1104*3448Sdh155122 	if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
1105*3448Sdh155122 		return (DLADM_STATUS_TEMPONLY);
1106*3448Sdh155122 
1107*3448Sdh155122 	if (pdp->pd_set == NULL)
1108*3448Sdh155122 		return (DLADM_STATUS_PROPRDONLY);
1109*3448Sdh155122 
1110*3448Sdh155122 	if (prop_val != NULL) {
1111*3448Sdh155122 		if (pdp->pd_check != NULL)
1112*3448Sdh155122 			status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
1113*3448Sdh155122 		else
1114*3448Sdh155122 			status = DLADM_STATUS_BADARG;
1115*3448Sdh155122 
1116*3448Sdh155122 		if (status != DLADM_STATUS_OK)
1117*3448Sdh155122 			return (status);
1118*3448Sdh155122 
1119*3448Sdh155122 		cnt = val_cnt;
1120*3448Sdh155122 	} else {
1121*3448Sdh155122 		if (pdp->pd_defval.vd_name == NULL)
1122*3448Sdh155122 			return (DLADM_STATUS_NOTSUP);
1123*3448Sdh155122 
1124*3448Sdh155122 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
1125*3448Sdh155122 			return (DLADM_STATUS_NOMEM);
1126*3448Sdh155122 
1127*3448Sdh155122 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
1128*3448Sdh155122 		cnt = 1;
1129*3448Sdh155122 	}
1130*3448Sdh155122 
1131*3448Sdh155122 	status = pdp->pd_set(link, vdp, cnt);
1132*3448Sdh155122 
1133*3448Sdh155122 	free(vdp);
1134*3448Sdh155122 	return (status);
1135*3448Sdh155122 }
1136*3448Sdh155122 
1137*3448Sdh155122 static dladm_status_t
1138*3448Sdh155122 i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val,
1139*3448Sdh155122     uint_t val_cnt, uint_t flags, char **errprop)
1140*3448Sdh155122 {
1141*3448Sdh155122 	int 		i;
1142*3448Sdh155122 	dladm_status_t	status = DLADM_STATUS_OK;
1143*3448Sdh155122 	boolean_t	found = B_FALSE;
1144*3448Sdh155122 
1145*3448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
1146*3448Sdh155122 		prop_desc_t	*pdp = &prop_table[i];
1147*3448Sdh155122 		dladm_status_t	s;
1148*3448Sdh155122 
1149*3448Sdh155122 		if (prop_name != NULL &&
1150*3448Sdh155122 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
1151*3448Sdh155122 			continue;
1152*3448Sdh155122 
1153*3448Sdh155122 		found = B_TRUE;
1154*3448Sdh155122 		s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt,
1155*3448Sdh155122 		    flags);
1156*3448Sdh155122 
1157*3448Sdh155122 		if (prop_name != NULL) {
1158*3448Sdh155122 			status = s;
1159*3448Sdh155122 			break;
1160*3448Sdh155122 		} else {
1161*3448Sdh155122 			if (s != DLADM_STATUS_OK &&
1162*3448Sdh155122 			    s != DLADM_STATUS_NOTSUP) {
1163*3448Sdh155122 				if (errprop != NULL)
1164*3448Sdh155122 					*errprop = pdp->pd_name;
1165*3448Sdh155122 				status = s;
1166*3448Sdh155122 				break;
1167*3448Sdh155122 			}
1168*3448Sdh155122 		}
1169*3448Sdh155122 	}
1170*3448Sdh155122 
1171*3448Sdh155122 	if (!found)
1172*3448Sdh155122 		status = DLADM_STATUS_NOTFOUND;
1173*3448Sdh155122 
1174*3448Sdh155122 	return (status);
1175*3448Sdh155122 }
1176*3448Sdh155122 
1177*3448Sdh155122 static boolean_t
1178*3448Sdh155122 i_dladm_is_prop_temponly(const char *prop_name, char **errprop)
1179*3448Sdh155122 {
1180*3448Sdh155122 	int 		i;
1181*3448Sdh155122 
1182*3448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
1183*3448Sdh155122 		prop_desc_t	*pdp = &prop_table[i];
1184*3448Sdh155122 
1185*3448Sdh155122 		if (prop_name != NULL &&
1186*3448Sdh155122 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
1187*3448Sdh155122 			continue;
1188*3448Sdh155122 
1189*3448Sdh155122 		if (errprop != NULL)
1190*3448Sdh155122 			*errprop = pdp->pd_name;
1191*3448Sdh155122 
1192*3448Sdh155122 		if (pdp->pd_temponly)
1193*3448Sdh155122 			return (B_TRUE);
1194*3448Sdh155122 	}
1195*3448Sdh155122 
1196*3448Sdh155122 	return (B_FALSE);
1197*3448Sdh155122 }
1198*3448Sdh155122 
1199*3448Sdh155122 boolean_t
1200*3448Sdh155122 dladm_is_prop_temponly(const char *prop_name, char **errprop)
1201*3448Sdh155122 {
1202*3448Sdh155122 	return (i_dladm_is_prop_temponly(prop_name, errprop));
1203*3448Sdh155122 }
1204