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 /*
223448Sdh155122  * 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>
323448Sdh155122 #include <sys/types.h>
333147Sxc151355 #include <sys/stat.h>
343448Sdh155122 #include <sys/dld.h>
353448Sdh155122 #include <sys/zone.h>
363448Sdh155122 #include <fcntl.h>
373448Sdh155122 #include <unistd.h>
383448Sdh155122 #include <libdevinfo.h>
393448Sdh155122 #include <zone.h>
40*3871Syz147064 #include <libdllink.h>
413147Sxc151355 #include <libdladm_impl.h>
42*3871Syz147064 #include <libdlwlan.h>
433448Sdh155122 #include <dlfcn.h>
443448Sdh155122 #include <link.h>
453448Sdh155122 
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 *);
503448Sdh155122 static dladm_status_t	i_dladm_get_prop_temp(const char *, dladm_prop_type_t,
513448Sdh155122 			    const char *, char **, uint_t *);
523448Sdh155122 static dladm_status_t	i_dladm_set_prop_temp(const char *, const char *,
533448Sdh155122 			    char **, uint_t, uint_t, char **);
543448Sdh155122 static boolean_t	i_dladm_is_prop_temponly(const char *prop_name,
553448Sdh155122 			    char **);
563448Sdh155122 
573448Sdh155122 typedef struct val_desc {
583448Sdh155122 	char	*vd_name;
593448Sdh155122 	void	*vd_val;
603448Sdh155122 } val_desc_t;
613448Sdh155122 
623448Sdh155122 struct prop_desc;
633448Sdh155122 
643448Sdh155122 typedef dladm_status_t	pd_getf_t(const char *, char **, uint_t *);
653448Sdh155122 typedef dladm_status_t	pd_setf_t(const char *, val_desc_t *, uint_t);
663448Sdh155122 typedef dladm_status_t	pd_checkf_t(struct prop_desc *, char **,
673448Sdh155122 			    uint_t, val_desc_t **);
683448Sdh155122 
693448Sdh155122 static pd_getf_t	do_get_zone;
703448Sdh155122 static pd_setf_t	do_set_zone;
713448Sdh155122 static pd_checkf_t	do_check_zone;
723448Sdh155122 
733448Sdh155122 typedef struct prop_desc {
743448Sdh155122 	char		*pd_name;
753448Sdh155122 	val_desc_t	pd_defval;
763448Sdh155122 	val_desc_t	*pd_modval;
773448Sdh155122 	uint_t		pd_nmodval;
783448Sdh155122 	boolean_t	pd_temponly;
793448Sdh155122 	pd_setf_t	*pd_set;
803448Sdh155122 	pd_getf_t	*pd_getmod;
813448Sdh155122 	pd_getf_t	*pd_get;
823448Sdh155122 	pd_checkf_t	*pd_check;
833448Sdh155122 } prop_desc_t;
843448Sdh155122 
853448Sdh155122 static prop_desc_t	prop_table[] = {
863448Sdh155122 	{ "zone",	{ "", NULL }, NULL, 0, B_TRUE,
873448Sdh155122 	    do_set_zone, NULL,
883448Sdh155122 	    do_get_zone, do_check_zone}
893448Sdh155122 };
903448Sdh155122 
913448Sdh155122 #define	MAX_PROPS	(sizeof (prop_table) / sizeof (prop_desc_t))
923147Sxc151355 
933147Sxc151355 dladm_status_t
943147Sxc151355 dladm_set_prop(const char *link, const char *prop_name, char **prop_val,
953448Sdh155122     uint_t val_cnt, uint_t flags, char **errprop)
963147Sxc151355 {
973147Sxc151355 	dladm_status_t		status = DLADM_STATUS_BADARG;
983147Sxc151355 
993147Sxc151355 	if (link == NULL || (prop_val == NULL && val_cnt > 0) ||
1003147Sxc151355 	    (prop_val != NULL && val_cnt == 0) || flags == 0)
1013147Sxc151355 		return (DLADM_STATUS_BADARG);
1023147Sxc151355 
1033147Sxc151355 	if ((flags & DLADM_OPT_TEMP) != 0) {
1043448Sdh155122 		status = i_dladm_set_prop_temp(link, prop_name, prop_val,
1053448Sdh155122 		    val_cnt, flags, errprop);
1063448Sdh155122 		if (status == DLADM_STATUS_TEMPONLY &&
1073448Sdh155122 		    (flags & DLADM_OPT_PERSIST) != 0)
1083448Sdh155122 			return (DLADM_STATUS_TEMPONLY);
1093448Sdh155122 
1103448Sdh155122 		if (status == DLADM_STATUS_NOTFOUND) {
1113448Sdh155122 			status = DLADM_STATUS_BADARG;
112*3871Syz147064 			if (dladm_wlan_is_valid(link)) {
113*3871Syz147064 				status = dladm_wlan_set_prop(link, prop_name,
114*3871Syz147064 				    prop_val, val_cnt, errprop);
1153448Sdh155122 			}
1163147Sxc151355 		}
1173147Sxc151355 		if (status != DLADM_STATUS_OK)
1183147Sxc151355 			return (status);
1193147Sxc151355 	}
1203147Sxc151355 	if ((flags & DLADM_OPT_PERSIST) != 0) {
1213448Sdh155122 		if (i_dladm_is_prop_temponly(prop_name, errprop))
1223448Sdh155122 			return (DLADM_STATUS_TEMPONLY);
1233448Sdh155122 
1243147Sxc151355 		status = i_dladm_set_prop_db(link, prop_name,
1253147Sxc151355 		    prop_val, val_cnt);
1263147Sxc151355 	}
1273147Sxc151355 	return (status);
1283147Sxc151355 }
1293147Sxc151355 
1303147Sxc151355 dladm_status_t
1313147Sxc151355 dladm_walk_prop(const char *link, void *arg,
1323147Sxc151355     boolean_t (*func)(void *, const char *))
1333147Sxc151355 {
1343448Sdh155122 	int	i;
1353448Sdh155122 
1363147Sxc151355 	if (link == NULL || func == NULL)
1373147Sxc151355 		return (DLADM_STATUS_BADARG);
1383147Sxc151355 
1393448Sdh155122 	/* For wifi links, show wifi properties first */
140*3871Syz147064 	if (dladm_wlan_is_valid(link)) {
1413448Sdh155122 		dladm_status_t	status;
1423448Sdh155122 
143*3871Syz147064 		status = dladm_wlan_walk_prop(link, arg, func);
1443448Sdh155122 		if (status != DLADM_STATUS_OK)
1453448Sdh155122 			return (status);
1463147Sxc151355 	}
1473448Sdh155122 
1483448Sdh155122 	/* Then show data-link properties if there are any */
1493448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
1503448Sdh155122 		if (!func(arg, prop_table[i].pd_name))
1513448Sdh155122 			break;
1523448Sdh155122 	}
1533448Sdh155122 	return (DLADM_STATUS_OK);
1543147Sxc151355 }
1553147Sxc151355 
1563147Sxc151355 dladm_status_t
1573147Sxc151355 dladm_get_prop(const char *link, dladm_prop_type_t type,
1583147Sxc151355     const char *prop_name, char **prop_val, uint_t *val_cntp)
1593147Sxc151355 {
1603448Sdh155122 	dladm_status_t status;
1613448Sdh155122 
1623147Sxc151355 	if (link == NULL || prop_name == NULL || prop_val == NULL ||
1633147Sxc151355 	    val_cntp == NULL || *val_cntp == 0)
1643147Sxc151355 		return (DLADM_STATUS_BADARG);
1653147Sxc151355 
1663147Sxc151355 	if (type == DLADM_PROP_VAL_PERSISTENT) {
167*3871Syz147064 		if (i_dladm_is_prop_temponly(prop_name, NULL))
168*3871Syz147064 			return (DLADM_STATUS_TEMPONLY);
1693147Sxc151355 		return (i_dladm_get_prop_db(link, prop_name,
1703147Sxc151355 		    prop_val, val_cntp));
1713147Sxc151355 	}
1723147Sxc151355 
1733448Sdh155122 	status = i_dladm_get_prop_temp(link, type, prop_name,
1743448Sdh155122 	    prop_val, val_cntp);
1753448Sdh155122 	if (status != DLADM_STATUS_NOTFOUND)
1763448Sdh155122 		return (status);
1773448Sdh155122 
178*3871Syz147064 	if (dladm_wlan_is_valid(link)) {
179*3871Syz147064 		return (dladm_wlan_get_prop(link, type, prop_name,
180*3871Syz147064 		    prop_val, val_cntp));
1813147Sxc151355 	}
1823147Sxc151355 	return (DLADM_STATUS_BADARG);
1833147Sxc151355 }
1843147Sxc151355 
1853147Sxc151355 /*
1863147Sxc151355  * Data structures used for implementing persistent link properties
1873147Sxc151355  */
1883147Sxc151355 typedef struct linkprop_val {
1893147Sxc151355 	const char		*lv_name;
1903147Sxc151355 	struct linkprop_val	*lv_nextval;
1913147Sxc151355 } linkprop_val_t;
1923147Sxc151355 
1933147Sxc151355 typedef struct linkprop_info {
1943147Sxc151355 	const char		*li_name;
1953147Sxc151355 	struct linkprop_info	*li_nextprop;
1963147Sxc151355 	struct linkprop_val	*li_val;
1973147Sxc151355 } linkprop_info_t;
1983147Sxc151355 
1993147Sxc151355 typedef struct linkprop_db_state	linkprop_db_state_t;
2003147Sxc151355 
2013147Sxc151355 typedef boolean_t (*linkprop_db_op_t)(linkprop_db_state_t *,
2023147Sxc151355     char *, linkprop_info_t *, dladm_status_t *);
2033147Sxc151355 
2043147Sxc151355 struct linkprop_db_state {
2053147Sxc151355 	linkprop_db_op_t	ls_op;
2063147Sxc151355 	const char		*ls_link;
2073147Sxc151355 	const char		*ls_propname;
2083147Sxc151355 	char			**ls_propval;
2093147Sxc151355 	uint_t			*ls_valcntp;
2103147Sxc151355 };
2113147Sxc151355 
2123147Sxc151355 static void
2133147Sxc151355 free_linkprops(linkprop_info_t *lip)
2143147Sxc151355 {
2153147Sxc151355 	linkprop_info_t	*lip_next;
2163147Sxc151355 	linkprop_val_t	*lvp, *lvp_next;
2173147Sxc151355 
2183147Sxc151355 	for (; lip != NULL; lip = lip_next) {
2193147Sxc151355 		lip_next = lip->li_nextprop;
2203147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
2213147Sxc151355 			lvp_next = lvp->lv_nextval;
2223147Sxc151355 			free(lvp);
2233147Sxc151355 		}
2243147Sxc151355 		free(lip);
2253147Sxc151355 	}
2263147Sxc151355 }
2273147Sxc151355 
2283147Sxc151355 /*
2293147Sxc151355  * Generate an entry in the link property database.
2303147Sxc151355  * Each entry has this format:
2313147Sxc151355  * <linkname>	<prop0>=<val0>,...,<valn>;...;<propn>=<val0>,...,<valn>;
2323147Sxc151355  */
2333147Sxc151355 static void
2343147Sxc151355 generate_linkprop_line(linkprop_db_state_t *lsp, char *buf,
2353147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
2363147Sxc151355 {
2373147Sxc151355 	char		tmpbuf[MAXLINELEN];
2383147Sxc151355 	char		*ptr, *lim = tmpbuf + MAXLINELEN;
2393147Sxc151355 	linkprop_info_t	*lip = listp;
2403147Sxc151355 	linkprop_val_t	*lvp = NULL;
2413147Sxc151355 
2423147Sxc151355 	/*
2433147Sxc151355 	 * Delete line if there are no properties left.
2443147Sxc151355 	 */
2453147Sxc151355 	if (lip == NULL ||
2463147Sxc151355 	    (lip->li_val == NULL && lip->li_nextprop == NULL)) {
2473147Sxc151355 		buf[0] = '\0';
2483147Sxc151355 		return;
2493147Sxc151355 	}
2503147Sxc151355 	ptr = tmpbuf;
2513147Sxc151355 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", lsp->ls_link);
2523147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
2533147Sxc151355 		/*
2543147Sxc151355 		 * Skip properties without values.
2553147Sxc151355 		 */
2563147Sxc151355 		if (lip->li_val == NULL)
2573147Sxc151355 			continue;
2583147Sxc151355 
2593147Sxc151355 		ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s=", lip->li_name);
2603147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
2613147Sxc151355 			ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s%c",
2623147Sxc151355 			    lvp->lv_name,
2633147Sxc151355 			    ((lvp->lv_nextval == NULL) ? ';' : ','));
2643147Sxc151355 		}
2653147Sxc151355 	}
2663147Sxc151355 	if (ptr > lim) {
2673147Sxc151355 		*statusp = DLADM_STATUS_TOOSMALL;
2683147Sxc151355 		return;
2693147Sxc151355 	}
2703147Sxc151355 	(void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
2713147Sxc151355 }
2723147Sxc151355 
2733147Sxc151355 /*
2743147Sxc151355  * This function is used to update or create an entry in the persistent db.
2753147Sxc151355  * process_linkprop_db() will first scan the db for an entry matching the
2763147Sxc151355  * specified link. If a match is found, this function is invoked with the
2773147Sxc151355  * entry's contents (buf) and its linked-list representation (listp). lsp
2783147Sxc151355  * holds the name and values of the property to be added or updated; this
2793147Sxc151355  * information will be merged with listp. Subsequently, an updated entry
2803147Sxc151355  * will be written to buf, which will in turn be written to disk by
2813147Sxc151355  * process_linkprop_db(). If no entry matches the specified link, listp
2823147Sxc151355  * will be NULL; a new entry will be generated in this case and it will
2833147Sxc151355  * contain only the property information in lsp.
2843147Sxc151355  */
2853147Sxc151355 static boolean_t
2863147Sxc151355 process_linkprop_set(linkprop_db_state_t *lsp, char *buf,
2873147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
2883147Sxc151355 {
2893147Sxc151355 	dladm_status_t	status;
2903147Sxc151355 	linkprop_info_t	*lastp = NULL, *lip = listp, *nlip = NULL;
2913147Sxc151355 	linkprop_val_t	**lvpp;
2923147Sxc151355 	int		i;
2933147Sxc151355 
2943147Sxc151355 	if (lsp->ls_propname == NULL) {
2953147Sxc151355 		buf[0] = '\0';
2963147Sxc151355 		return (B_FALSE);
2973147Sxc151355 	}
2983147Sxc151355 
2993147Sxc151355 	/*
3003147Sxc151355 	 * Find the linkprop we want to change.
3013147Sxc151355 	 */
3023147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
3033147Sxc151355 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
3043147Sxc151355 			break;
3053147Sxc151355 
3063147Sxc151355 		lastp = lip;
3073147Sxc151355 	}
3083147Sxc151355 
3093147Sxc151355 	if (lip == NULL) {
3103147Sxc151355 		/*
3113147Sxc151355 		 * If the linkprop is not found, append it to the list.
3123147Sxc151355 		 */
3133147Sxc151355 		if ((nlip = malloc(sizeof (linkprop_info_t))) == NULL) {
3143147Sxc151355 			status = DLADM_STATUS_NOMEM;
3153147Sxc151355 			goto fail;
3163147Sxc151355 		}
3173147Sxc151355 		/*
3183147Sxc151355 		 * nlip will need to be freed later if there is no list to
3193147Sxc151355 		 * append to.
3203147Sxc151355 		 */
3213147Sxc151355 		if (lastp != NULL)
3223147Sxc151355 			lastp->li_nextprop = nlip;
3233147Sxc151355 		nlip->li_name = lsp->ls_propname;
3243147Sxc151355 		nlip->li_nextprop = NULL;
3253147Sxc151355 		nlip->li_val = NULL;
3263147Sxc151355 		lvpp = &nlip->li_val;
3273147Sxc151355 	} else {
3283147Sxc151355 		linkprop_val_t	*lvp, *lvp_next;
3293147Sxc151355 
3303147Sxc151355 		/*
3313147Sxc151355 		 * If the linkprop is found, delete the existing values from it.
3323147Sxc151355 		 */
3333147Sxc151355 		for (lvp = lip->li_val; lvp != NULL; lvp = lvp_next) {
3343147Sxc151355 			lvp_next = lvp->lv_nextval;
3353147Sxc151355 			free(lvp);
3363147Sxc151355 		}
3373147Sxc151355 		lip->li_val = NULL;
3383147Sxc151355 		lvpp = &lip->li_val;
3393147Sxc151355 	}
3403147Sxc151355 
3413147Sxc151355 	/*
3423147Sxc151355 	 * Fill our linkprop with the specified values.
3433147Sxc151355 	 */
3443147Sxc151355 	for (i = 0; i < *lsp->ls_valcntp; i++) {
3453147Sxc151355 		if ((*lvpp = malloc(sizeof (linkprop_val_t))) == NULL) {
3463147Sxc151355 			status = DLADM_STATUS_NOMEM;
3473147Sxc151355 			goto fail;
3483147Sxc151355 		}
3493147Sxc151355 		(*lvpp)->lv_name = lsp->ls_propval[i];
3503147Sxc151355 		(*lvpp)->lv_nextval = NULL;
3513147Sxc151355 		lvpp = &(*lvpp)->lv_nextval;
3523147Sxc151355 	}
3533147Sxc151355 
3543147Sxc151355 	if (listp != NULL) {
3553147Sxc151355 		generate_linkprop_line(lsp, buf, listp, statusp);
3563147Sxc151355 	} else {
3573147Sxc151355 		generate_linkprop_line(lsp, buf, nlip, statusp);
3583147Sxc151355 		free_linkprops(nlip);
3593147Sxc151355 	}
3603147Sxc151355 	return (B_FALSE);
3613147Sxc151355 
3623147Sxc151355 fail:
3633147Sxc151355 	*statusp = status;
3643147Sxc151355 	if (listp == NULL)
3653147Sxc151355 		free_linkprops(nlip);
3663147Sxc151355 
3673147Sxc151355 	return (B_FALSE);
3683147Sxc151355 }
3693147Sxc151355 
3703147Sxc151355 /*
3713147Sxc151355  * This function is used for retrieving the values for a specific property.
3723147Sxc151355  * It gets called if an entry matching the specified link exists in the db.
3733147Sxc151355  * The entry is converted into a linked-list listp. This list is then scanned
3743147Sxc151355  * for the specified property name; if a matching property exists, its
3753147Sxc151355  * associated values are copied to the array lsp->ls_propval.
3763147Sxc151355  */
3773147Sxc151355 /* ARGSUSED */
3783147Sxc151355 static boolean_t
3793147Sxc151355 process_linkprop_get(linkprop_db_state_t *lsp, char *buf,
3803147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
3813147Sxc151355 {
3823147Sxc151355 	linkprop_info_t	*lip = listp;
3833147Sxc151355 	linkprop_val_t	*lvp;
3843147Sxc151355 	uint_t		valcnt = 0;
3853147Sxc151355 
3863147Sxc151355 	/*
3873147Sxc151355 	 * Find the linkprop we want to get.
3883147Sxc151355 	 */
3893147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
3903147Sxc151355 		if (strcmp(lip->li_name, lsp->ls_propname) == 0)
3913147Sxc151355 			break;
3923147Sxc151355 	}
3933147Sxc151355 	if (lip == NULL) {
3943147Sxc151355 		*statusp = DLADM_STATUS_NOTFOUND;
3953147Sxc151355 		return (B_FALSE);
3963147Sxc151355 	}
3973147Sxc151355 
3983147Sxc151355 	for (lvp = lip->li_val; lvp != NULL; lvp = lvp->lv_nextval) {
3993147Sxc151355 		(void) strncpy(lsp->ls_propval[valcnt], lvp->lv_name,
4003147Sxc151355 		    DLADM_PROP_VAL_MAX);
4013147Sxc151355 
4023147Sxc151355 		if (++valcnt >= *lsp->ls_valcntp && lvp->lv_nextval != NULL) {
4033147Sxc151355 			*statusp = DLADM_STATUS_TOOSMALL;
4043147Sxc151355 			return (B_FALSE);
4053147Sxc151355 		}
4063147Sxc151355 	}
4073147Sxc151355 	/*
4083147Sxc151355 	 * This function is meant to be called at most once for each call
4093147Sxc151355 	 * to process_linkprop_db(). For this reason, it's ok to overwrite
4103147Sxc151355 	 * the caller's valcnt array size with the actual number of values
4113147Sxc151355 	 * returned.
4123147Sxc151355 	 */
4133147Sxc151355 	*lsp->ls_valcntp = valcnt;
4143147Sxc151355 	return (B_FALSE);
4153147Sxc151355 }
4163147Sxc151355 
4173147Sxc151355 /*
4183147Sxc151355  * This is used for initializing link properties.
4193147Sxc151355  * Unlike the other routines, this gets called for every entry in the
4203147Sxc151355  * database. lsp->ls_link is not user-specified but instead is set to
4213147Sxc151355  * the current link being processed.
4223147Sxc151355  */
4233147Sxc151355 /* ARGSUSED */
4243147Sxc151355 static boolean_t
4253147Sxc151355 process_linkprop_init(linkprop_db_state_t *lsp, char *buf,
4263147Sxc151355     linkprop_info_t *listp, dladm_status_t *statusp)
4273147Sxc151355 {
4283147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
4293147Sxc151355 	linkprop_info_t	*lip = listp;
4303147Sxc151355 	linkprop_val_t	*lvp;
4313147Sxc151355 	uint_t		valcnt, i;
4323147Sxc151355 	char		**propval;
4333147Sxc151355 
4343147Sxc151355 	for (; lip != NULL; lip = lip->li_nextprop) {
4353147Sxc151355 		/*
4363147Sxc151355 		 * Construct the propval array and fill it with
4373147Sxc151355 		 * values from listp.
4383147Sxc151355 		 */
4393147Sxc151355 		for (lvp = lip->li_val, valcnt = 0;
4403147Sxc151355 		    lvp != NULL; lvp = lvp->lv_nextval, valcnt++);
4413147Sxc151355 
4423147Sxc151355 		propval = malloc(sizeof (char *) * valcnt);
4433147Sxc151355 		if (propval == NULL) {
4443147Sxc151355 			*statusp = DLADM_STATUS_NOMEM;
4453147Sxc151355 			break;
4463147Sxc151355 		}
4473147Sxc151355 		lvp = lip->li_val;
4483147Sxc151355 		for (i = 0; i < valcnt; i++, lvp = lvp->lv_nextval)
4493147Sxc151355 			propval[i] = (char *)lvp->lv_name;
4503147Sxc151355 
4513147Sxc151355 		status = dladm_set_prop(lsp->ls_link, lip->li_name,
4523448Sdh155122 		    propval, valcnt, DLADM_OPT_TEMP, NULL);
4533147Sxc151355 
4543147Sxc151355 		/*
4553147Sxc151355 		 * We continue with initializing other properties even
4563147Sxc151355 		 * after encountering an error. This error will be
4573147Sxc151355 		 * propagated to the caller via 'statusp'.
4583147Sxc151355 		 */
4593147Sxc151355 		if (status != DLADM_STATUS_OK)
4603147Sxc151355 			*statusp = status;
4613147Sxc151355 
4623147Sxc151355 		free(propval);
4633147Sxc151355 	}
4643147Sxc151355 	return (B_TRUE);
4653147Sxc151355 }
4663147Sxc151355 
4673147Sxc151355 static int
4683147Sxc151355 parse_linkprops(char *buf, linkprop_info_t **lipp)
4693147Sxc151355 {
4703147Sxc151355 	int			i, len;
4713147Sxc151355 	char			*curr;
4723147Sxc151355 	linkprop_info_t		*lip = NULL;
4733147Sxc151355 	linkprop_info_t		**tailp = lipp;
4743147Sxc151355 	linkprop_val_t		*lvp = NULL;
4753147Sxc151355 	linkprop_val_t		**vtailp = NULL;
4763147Sxc151355 
4773147Sxc151355 	curr = buf;
4783147Sxc151355 	len = strlen(buf);
4793147Sxc151355 	for (i = 0; i < len; i++) {
4803147Sxc151355 		char		c = buf[i];
4813147Sxc151355 		boolean_t	match = (c == '=' || c == ',' || c == ';');
4823147Sxc151355 
4833147Sxc151355 		/*
4843147Sxc151355 		 * Move to the next character if there is no match and
4853147Sxc151355 		 * if we have not reached the last character.
4863147Sxc151355 		 */
4873147Sxc151355 		if (!match && i != len - 1)
4883147Sxc151355 			continue;
4893147Sxc151355 
4903147Sxc151355 		if (match) {
4913147Sxc151355 			/*
4923147Sxc151355 			 * Nul-terminate the string pointed to by 'curr'.
4933147Sxc151355 			 */
4943147Sxc151355 			buf[i] = '\0';
4953147Sxc151355 			if (*curr == '\0')
4963147Sxc151355 				goto fail;
4973147Sxc151355 		}
4983147Sxc151355 
4993147Sxc151355 		if (lip != NULL) {
5003147Sxc151355 			/*
5013147Sxc151355 			 * We get here after we have processed the "<prop>="
5023147Sxc151355 			 * pattern. The pattern we are now interested in is
5033147Sxc151355 			 * "<val0>,<val1>,...,<valn>;". For each value we
5043147Sxc151355 			 * find, a linkprop_val_t will be allocated and
5053147Sxc151355 			 * added to the current 'lip'.
5063147Sxc151355 			 */
5073147Sxc151355 			if (c == '=')
5083147Sxc151355 				goto fail;
5093147Sxc151355 
5103147Sxc151355 			lvp = malloc(sizeof (*lvp));
5113147Sxc151355 			if (lvp == NULL)
5123147Sxc151355 				goto fail;
5133147Sxc151355 
5143147Sxc151355 			lvp->lv_name = curr;
5153147Sxc151355 			lvp->lv_nextval = NULL;
5163147Sxc151355 			*vtailp = lvp;
5173147Sxc151355 			vtailp = &lvp->lv_nextval;
5183147Sxc151355 
5193147Sxc151355 			if (c == ';') {
5203147Sxc151355 				tailp = &lip->li_nextprop;
5213147Sxc151355 				vtailp = NULL;
5223147Sxc151355 				lip = NULL;
5233147Sxc151355 			}
5243147Sxc151355 		} else {
5253147Sxc151355 			/*
5263147Sxc151355 			 * lip == NULL indicates that 'curr' must be refering
5273147Sxc151355 			 * to a property name. We allocate a new linkprop_info_t
5283147Sxc151355 			 * append it to the list given by the caller.
5293147Sxc151355 			 */
5303147Sxc151355 			if (c != '=')
5313147Sxc151355 				goto fail;
5323147Sxc151355 
5333147Sxc151355 			lip = malloc(sizeof (*lip));
5343147Sxc151355 			if (lip == NULL)
5353147Sxc151355 				goto fail;
5363147Sxc151355 
5373147Sxc151355 			lip->li_name = curr;
5383147Sxc151355 			lip->li_val = NULL;
5393147Sxc151355 			lip->li_nextprop = NULL;
5403147Sxc151355 			*tailp = lip;
5413147Sxc151355 			vtailp = &lip->li_val;
5423147Sxc151355 		}
5433147Sxc151355 		curr = buf + i + 1;
5443147Sxc151355 	}
5453147Sxc151355 	/*
5463147Sxc151355 	 * The list must be non-empty and the last character must be ';'.
5473147Sxc151355 	 */
5483147Sxc151355 	if (*lipp == NULL || lip != NULL)
5493147Sxc151355 		goto fail;
5503147Sxc151355 
5513147Sxc151355 	return (0);
5523147Sxc151355 
5533147Sxc151355 fail:
5543147Sxc151355 	free_linkprops(*lipp);
5553147Sxc151355 	*lipp = NULL;
5563147Sxc151355 	return (-1);
5573147Sxc151355 }
5583147Sxc151355 
5593147Sxc151355 static boolean_t
5603147Sxc151355 process_linkprop_line(linkprop_db_state_t *lsp, char *buf,
5613147Sxc151355     dladm_status_t *statusp)
5623147Sxc151355 {
5633147Sxc151355 	linkprop_info_t		*lip = NULL;
5643147Sxc151355 	int			i, len, llen;
5653147Sxc151355 	char			*str, *lasts;
5663147Sxc151355 	boolean_t		cont, nolink = B_FALSE;
5673147Sxc151355 
5683147Sxc151355 	/*
5693147Sxc151355 	 * Skip leading spaces, blank lines, and comments.
5703147Sxc151355 	 */
5713147Sxc151355 	len = strlen(buf);
5723147Sxc151355 	for (i = 0; i < len; i++) {
5733147Sxc151355 		if (!isspace(buf[i]))
5743147Sxc151355 			break;
5753147Sxc151355 	}
5763147Sxc151355 	if (i == len || buf[i] == '#')
5773147Sxc151355 		return (B_TRUE);
5783147Sxc151355 
5793147Sxc151355 	str = buf + i;
5803147Sxc151355 	if (lsp->ls_link != NULL) {
5813147Sxc151355 		/*
5823147Sxc151355 		 * Skip links we're not interested in.
5833147Sxc151355 		 * Note that strncmp() and isspace() are used here
5843147Sxc151355 		 * instead of strtok() and strcmp() because we don't
5853147Sxc151355 		 * want to modify buf in case it does not contain the
5863147Sxc151355 		 * specified link.
5873147Sxc151355 		 */
5883147Sxc151355 		llen = strlen(lsp->ls_link);
5893147Sxc151355 		if (strncmp(str, lsp->ls_link, llen) != 0 ||
5903147Sxc151355 		    !isspace(str[llen]))
5913147Sxc151355 			return (B_TRUE);
5923147Sxc151355 	} else {
5933147Sxc151355 		/*
5943147Sxc151355 		 * If a link is not specified, find the link name
5953147Sxc151355 		 * and assign it to lsp->ls_link.
5963147Sxc151355 		 */
5973147Sxc151355 		if (strtok_r(str, " \n\t", &lasts) == NULL)
5983147Sxc151355 			goto fail;
5993147Sxc151355 
6003147Sxc151355 		llen = strlen(str);
6013147Sxc151355 		lsp->ls_link = str;
6023147Sxc151355 		nolink = B_TRUE;
6033147Sxc151355 	}
6043147Sxc151355 	str += llen + 1;
6053147Sxc151355 	if (str >= buf + len)
6063147Sxc151355 		goto fail;
6073147Sxc151355 
6083147Sxc151355 	/*
6093147Sxc151355 	 * Now find the list of link properties.
6103147Sxc151355 	 */
6113147Sxc151355 	if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
6123147Sxc151355 		goto fail;
6133147Sxc151355 
6143147Sxc151355 	if (parse_linkprops(str, &lip) < 0)
6153147Sxc151355 		goto fail;
6163147Sxc151355 
6173147Sxc151355 	cont = (*lsp->ls_op)(lsp, buf, lip, statusp);
6183147Sxc151355 	free_linkprops(lip);
6193147Sxc151355 	if (nolink)
6203147Sxc151355 		lsp->ls_link = NULL;
6213147Sxc151355 	return (cont);
6223147Sxc151355 
6233147Sxc151355 fail:
6243147Sxc151355 	free_linkprops(lip);
6253147Sxc151355 	if (nolink)
6263147Sxc151355 		lsp->ls_link = NULL;
6273147Sxc151355 
6283147Sxc151355 	/*
6293147Sxc151355 	 * Delete corrupted line.
6303147Sxc151355 	 */
6313147Sxc151355 	buf[0] = '\0';
6323147Sxc151355 	return (B_TRUE);
6333147Sxc151355 }
6343147Sxc151355 
6353147Sxc151355 static dladm_status_t
6363147Sxc151355 process_linkprop_db(void *arg, FILE *fp, FILE *nfp)
6373147Sxc151355 {
6383147Sxc151355 	linkprop_db_state_t	*lsp = arg;
6393147Sxc151355 	dladm_status_t		status = DLADM_STATUS_OK;
6403147Sxc151355 	char			buf[MAXLINELEN];
6413147Sxc151355 	boolean_t		cont = B_TRUE;
6423147Sxc151355 
6433147Sxc151355 	/*
6443147Sxc151355 	 * This loop processes each line of the configuration file.
6453147Sxc151355 	 * buf can potentially be modified by process_linkprop_line().
6463147Sxc151355 	 * If this is a write operation and buf is not truncated, buf will
6473147Sxc151355 	 * be written to disk. process_linkprop_line() will no longer be
6483147Sxc151355 	 * called after it returns B_FALSE; at which point the remainder
6493147Sxc151355 	 * of the file will continue to be read and, if necessary, written
6503147Sxc151355 	 * to disk as well.
6513147Sxc151355 	 */
6523147Sxc151355 	while (fgets(buf, MAXLINELEN, fp) != NULL) {
6533147Sxc151355 		if (cont)
6543147Sxc151355 			cont = process_linkprop_line(lsp, buf, &status);
6553147Sxc151355 
6563147Sxc151355 		if (nfp != NULL && buf[0] != '\0' && fputs(buf, nfp) == EOF) {
6573147Sxc151355 			status = dladm_errno2status(errno);
6583147Sxc151355 			break;
6593147Sxc151355 		}
6603147Sxc151355 	}
6613147Sxc151355 
6623147Sxc151355 	if (status != DLADM_STATUS_OK || !cont)
6633147Sxc151355 		return (status);
6643147Sxc151355 
6653147Sxc151355 	if (lsp->ls_op == process_linkprop_set) {
6663147Sxc151355 		/*
6673147Sxc151355 		 * If the specified link is not found above, we add the
6683147Sxc151355 		 * link and its properties to the configuration file.
6693147Sxc151355 		 */
6703147Sxc151355 		(void) (*lsp->ls_op)(lsp, buf, NULL, &status);
6713147Sxc151355 		if (status == DLADM_STATUS_OK && fputs(buf, nfp) == EOF)
6723147Sxc151355 			status = dladm_errno2status(errno);
6733147Sxc151355 	}
6743147Sxc151355 
6753147Sxc151355 	if (lsp->ls_op == process_linkprop_get)
6763147Sxc151355 		status = DLADM_STATUS_NOTFOUND;
6773147Sxc151355 
6783147Sxc151355 	return (status);
6793147Sxc151355 }
6803147Sxc151355 
6813147Sxc151355 #define	LINKPROP_RW_DB(statep, writeop) \
6823147Sxc151355 	(i_dladm_rw_db("/etc/dladm/linkprop.conf", \
6833147Sxc151355 	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, process_linkprop_db, \
6843147Sxc151355 	(statep), (writeop)))
6853147Sxc151355 
6863147Sxc151355 static dladm_status_t
6873147Sxc151355 i_dladm_set_prop_db(const char *link, const char *prop_name,
6883147Sxc151355     char **prop_val, uint_t val_cnt)
6893147Sxc151355 {
6903147Sxc151355 	linkprop_db_state_t	state;
6913147Sxc151355 
6923147Sxc151355 	state.ls_op = process_linkprop_set;
6933147Sxc151355 	state.ls_link = link;
6943147Sxc151355 	state.ls_propname = prop_name;
6953147Sxc151355 	state.ls_propval = prop_val;
6963147Sxc151355 	state.ls_valcntp = &val_cnt;
6973147Sxc151355 
6983147Sxc151355 	return (LINKPROP_RW_DB(&state, B_TRUE));
6993147Sxc151355 }
7003147Sxc151355 
7013147Sxc151355 static dladm_status_t
7023147Sxc151355 i_dladm_get_prop_db(const char *link, const char *prop_name,
7033147Sxc151355     char **prop_val, uint_t *val_cntp)
7043147Sxc151355 {
7053147Sxc151355 	linkprop_db_state_t	state;
7063147Sxc151355 
7073147Sxc151355 	state.ls_op = process_linkprop_get;
7083147Sxc151355 	state.ls_link = link;
7093147Sxc151355 	state.ls_propname = prop_name;
7103147Sxc151355 	state.ls_propval = prop_val;
7113147Sxc151355 	state.ls_valcntp = val_cntp;
7123147Sxc151355 
7133147Sxc151355 	return (LINKPROP_RW_DB(&state, B_FALSE));
7143147Sxc151355 }
7153147Sxc151355 
7163147Sxc151355 dladm_status_t
7173147Sxc151355 dladm_init_linkprop(void)
7183147Sxc151355 {
7193147Sxc151355 	linkprop_db_state_t	state;
7203147Sxc151355 
7213147Sxc151355 	state.ls_op = process_linkprop_init;
7223147Sxc151355 	state.ls_link = NULL;
7233147Sxc151355 	state.ls_propname = NULL;
7243147Sxc151355 	state.ls_propval = NULL;
7253147Sxc151355 	state.ls_valcntp = NULL;
7263147Sxc151355 
7273147Sxc151355 	return (LINKPROP_RW_DB(&state, B_FALSE));
7283147Sxc151355 }
7293448Sdh155122 
7303448Sdh155122 static dladm_status_t
7313448Sdh155122 i_dladm_get_zoneid(const char *link, zoneid_t *zidp)
7323448Sdh155122 {
7333448Sdh155122 	int fd;
7343448Sdh155122 	dld_hold_vlan_t	dhv;
7353448Sdh155122 
7363448Sdh155122 	if ((fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
7373448Sdh155122 		return (dladm_errno2status(errno));
7383448Sdh155122 
7393448Sdh155122 	bzero(&dhv, sizeof (dld_hold_vlan_t));
7403448Sdh155122 	(void) strlcpy(dhv.dhv_name, link, IFNAMSIZ);
7413448Sdh155122 	dhv.dhv_zid = -1;
7423448Sdh155122 
7433448Sdh155122 	if (i_dladm_ioctl(fd, DLDIOCZIDGET, &dhv, sizeof (dhv)) < 0 &&
7443448Sdh155122 	    errno != ENOENT) {
7453448Sdh155122 		dladm_status_t status = dladm_errno2status(errno);
7463448Sdh155122 
7473448Sdh155122 		(void) close(fd);
7483448Sdh155122 		return (status);
7493448Sdh155122 	}
7503448Sdh155122 
7513448Sdh155122 	if (errno == ENOENT)
7523448Sdh155122 		*zidp = GLOBAL_ZONEID;
7533448Sdh155122 	else
7543448Sdh155122 		*zidp = dhv.dhv_zid;
7553448Sdh155122 
7563448Sdh155122 	(void) close(fd);
7573448Sdh155122 	return (DLADM_STATUS_OK);
7583448Sdh155122 }
7593448Sdh155122 
7603448Sdh155122 typedef int (*zone_get_devroot_t)(char *, char *, size_t);
7613448Sdh155122 
7623448Sdh155122 static int
7633448Sdh155122 i_dladm_get_zone_dev(char *zone_name, char *dev, size_t devlen)
7643448Sdh155122 {
7653448Sdh155122 	char			root[MAXPATHLEN];
7663448Sdh155122 	zone_get_devroot_t	real_zone_get_devroot;
7673448Sdh155122 	void			*dlhandle;
7683448Sdh155122 	void			*sym;
7693448Sdh155122 	int			ret;
7703448Sdh155122 
7713448Sdh155122 	if ((dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY)) == NULL)
7723448Sdh155122 		return (-1);
7733448Sdh155122 
7743448Sdh155122 	if ((sym = dlsym(dlhandle, "zone_get_devroot")) == NULL) {
7753448Sdh155122 		(void) dlclose(dlhandle);
7763448Sdh155122 		return (-1);
7773448Sdh155122 	}
7783448Sdh155122 
7793448Sdh155122 	real_zone_get_devroot = (zone_get_devroot_t)sym;
7803448Sdh155122 
7813448Sdh155122 	if ((ret = real_zone_get_devroot(zone_name, root, sizeof (root))) == 0)
7823448Sdh155122 		(void) snprintf(dev, devlen, "%s%s", root, "/dev");
7833448Sdh155122 	(void) dlclose(dlhandle);
7843448Sdh155122 	return (ret);
7853448Sdh155122 }
7863448Sdh155122 
7873448Sdh155122 static dladm_status_t
7883448Sdh155122 i_dladm_add_deventry(zoneid_t zid, const char *link)
7893448Sdh155122 {
7903448Sdh155122 	char		path[MAXPATHLEN];
7913448Sdh155122 	di_prof_t	prof = NULL;
7923448Sdh155122 	char		zone_name[ZONENAME_MAX];
7933448Sdh155122 	dladm_status_t	status;
7943448Sdh155122 
7953448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
7963448Sdh155122 		return (dladm_errno2status(errno));
7973448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
7983448Sdh155122 		return (dladm_errno2status(errno));
7993448Sdh155122 	if (di_prof_init(path, &prof) != 0)
8003448Sdh155122 		return (dladm_errno2status(errno));
8013448Sdh155122 
8023448Sdh155122 	status = DLADM_STATUS_OK;
8033448Sdh155122 	if (di_prof_add_dev(prof, link) != 0) {
8043448Sdh155122 		status = dladm_errno2status(errno);
8053448Sdh155122 		goto cleanup;
8063448Sdh155122 	}
8073448Sdh155122 	if (di_prof_commit(prof) != 0)
8083448Sdh155122 		status = dladm_errno2status(errno);
8093448Sdh155122 cleanup:
8103448Sdh155122 	if (prof)
8113448Sdh155122 		di_prof_fini(prof);
8123448Sdh155122 
8133448Sdh155122 	return (status);
8143448Sdh155122 }
8153448Sdh155122 
8163448Sdh155122 static dladm_status_t
8173448Sdh155122 i_dladm_remove_deventry(zoneid_t zid, const char *link)
8183448Sdh155122 {
8193448Sdh155122 	char		path[MAXPATHLEN];
8203448Sdh155122 	di_prof_t	prof = NULL;
8213448Sdh155122 	char		zone_name[ZONENAME_MAX];
8223448Sdh155122 	dladm_status_t	status;
8233448Sdh155122 
8243448Sdh155122 	if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
8253448Sdh155122 		return (dladm_errno2status(errno));
8263448Sdh155122 	if (i_dladm_get_zone_dev(zone_name, path, sizeof (path)) != 0)
8273448Sdh155122 		return (dladm_errno2status(errno));
8283448Sdh155122 	if (di_prof_init(path, &prof) != 0)
8293448Sdh155122 		return (dladm_errno2status(errno));
8303448Sdh155122 
8313448Sdh155122 	status = DLADM_STATUS_OK;
8323448Sdh155122 	if (di_prof_add_exclude(prof, link) != 0) {
8333448Sdh155122 		status = dladm_errno2status(errno);
8343448Sdh155122 		goto cleanup;
8353448Sdh155122 	}
8363448Sdh155122 	if (di_prof_commit(prof) != 0)
8373448Sdh155122 		status = dladm_errno2status(errno);
8383448Sdh155122 cleanup:
8393448Sdh155122 	if (prof)
8403448Sdh155122 		di_prof_fini(prof);
8413448Sdh155122 
8423448Sdh155122 	return (status);
8433448Sdh155122 }
8443448Sdh155122 
8453448Sdh155122 static dladm_status_t
8463448Sdh155122 do_get_zone(const char *link, char **prop_val, uint_t *val_cnt)
8473448Sdh155122 {
8483448Sdh155122 	char		zone_name[ZONENAME_MAX];
8493448Sdh155122 	zoneid_t	zid;
8503448Sdh155122 	dladm_status_t	status;
8513448Sdh155122 
8523448Sdh155122 	status = i_dladm_get_zoneid(link, &zid);
8533448Sdh155122 	if (status != DLADM_STATUS_OK)
8543448Sdh155122 		return (status);
8553448Sdh155122 
8563448Sdh155122 	*val_cnt = 1;
8573448Sdh155122 	if (zid != GLOBAL_ZONEID) {
8583448Sdh155122 		if (getzonenamebyid(zid, zone_name, sizeof (zone_name)) < 0)
8593448Sdh155122 			return (dladm_errno2status(errno));
8603448Sdh155122 
8613448Sdh155122 		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
8623448Sdh155122 	} else {
8633448Sdh155122 		*prop_val[0] = '\0';
8643448Sdh155122 	}
8653448Sdh155122 
8663448Sdh155122 	return (DLADM_STATUS_OK);
8673448Sdh155122 }
8683448Sdh155122 
8693448Sdh155122 static dladm_status_t
8703448Sdh155122 do_set_zone(const char *link, val_desc_t *vdp, uint_t val_cnt)
8713448Sdh155122 {
8723448Sdh155122 	dladm_status_t	status;
8733448Sdh155122 	zoneid_t	zid_old, zid_new;
8743448Sdh155122 	char		buff[IF_NAMESIZE + 1];
8753448Sdh155122 	struct stat	st;
8763448Sdh155122 
8773448Sdh155122 	if (val_cnt != 1)
8783448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
8793448Sdh155122 
8803448Sdh155122 	status = i_dladm_get_zoneid(link, &zid_old);
8813448Sdh155122 	if (status != DLADM_STATUS_OK)
8823448Sdh155122 		return (status);
8833448Sdh155122 
8843448Sdh155122 	/* Do nothing if setting to current value */
8853448Sdh155122 	zid_new = (zoneid_t)vdp->vd_val;
8863448Sdh155122 	if (zid_new == zid_old)
8873448Sdh155122 		return (DLADM_STATUS_OK);
8883448Sdh155122 
8893448Sdh155122 	/* Do a stat to get the vlan created by MAC, if it's not there */
8903448Sdh155122 	(void) strcpy(buff, "/dev/");
8913448Sdh155122 	(void) strlcat(buff, link, IF_NAMESIZE);
8923448Sdh155122 	(void) stat(buff, &st);
8933448Sdh155122 
8943448Sdh155122 	if (zid_old != GLOBAL_ZONEID) {
8953448Sdh155122 		if (dladm_rele_link(link, GLOBAL_ZONEID, B_TRUE) < 0)
8963448Sdh155122 			return (dladm_errno2status(errno));
8973448Sdh155122 
8983448Sdh155122 		if (zone_remove_datalink(zid_old, (char *)link) != 0 &&
8993448Sdh155122 		    errno != ENXIO) {
9003448Sdh155122 			status = dladm_errno2status(errno);
9013448Sdh155122 			goto rollback1;
9023448Sdh155122 		}
9033448Sdh155122 
9043448Sdh155122 		status = i_dladm_remove_deventry(zid_old, link);
9053448Sdh155122 		if (status != DLADM_STATUS_OK)
9063448Sdh155122 			goto rollback2;
9073448Sdh155122 	}
9083448Sdh155122 
9093448Sdh155122 	if (zid_new != GLOBAL_ZONEID) {
9103448Sdh155122 		if (zone_add_datalink(zid_new, (char *)link) != 0) {
9113448Sdh155122 			status = dladm_errno2status(errno);
9123448Sdh155122 			goto rollback3;
9133448Sdh155122 		}
9143448Sdh155122 
9153448Sdh155122 		if (dladm_hold_link(link, zid_new, B_TRUE) < 0) {
9163448Sdh155122 			(void) zone_remove_datalink(zid_new, (char *)link);
9173448Sdh155122 			status = dladm_errno2status(errno);
9183448Sdh155122 			goto rollback3;
9193448Sdh155122 		}
9203448Sdh155122 
9213448Sdh155122 		status = i_dladm_add_deventry(zid_new, link);
9223448Sdh155122 		if (status != DLADM_STATUS_OK) {
9233448Sdh155122 			(void) dladm_rele_link(link, GLOBAL_ZONEID, B_FALSE);
9243448Sdh155122 			(void) zone_remove_datalink(zid_new, (char *)link);
9253448Sdh155122 			goto rollback3;
9263448Sdh155122 		}
9273448Sdh155122 	}
9283448Sdh155122 	return (DLADM_STATUS_OK);
9293448Sdh155122 
9303448Sdh155122 rollback3:
9313448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
9323448Sdh155122 		(void) i_dladm_add_deventry(zid_old, link);
9333448Sdh155122 rollback2:
9343448Sdh155122 	if (zid_old != GLOBAL_ZONEID)
9353448Sdh155122 		(void) zone_add_datalink(zid_old, (char *)link);
9363448Sdh155122 rollback1:
9373448Sdh155122 	(void) dladm_hold_link(link, zid_old, B_FALSE);
9383448Sdh155122 cleanexit:
9393448Sdh155122 	return (status);
9403448Sdh155122 }
9413448Sdh155122 
9423448Sdh155122 /* ARGSUSED */
9433448Sdh155122 static dladm_status_t
9443448Sdh155122 do_check_zone(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
9453448Sdh155122     val_desc_t **vdpp)
9463448Sdh155122 {
9473448Sdh155122 	zoneid_t 	zid;
9483448Sdh155122 	val_desc_t	*vdp = NULL;
9493448Sdh155122 
9503448Sdh155122 	if (val_cnt != 1)
9513448Sdh155122 		return (DLADM_STATUS_BADVALCNT);
9523448Sdh155122 
9533448Sdh155122 	if ((zid = getzoneidbyname(*prop_val)) == -1)
9543448Sdh155122 		return (DLADM_STATUS_BADVAL);
9553448Sdh155122 
9563448Sdh155122 	if (zid != GLOBAL_ZONEID) {
9573448Sdh155122 		ushort_t	flags;
9583448Sdh155122 
9593448Sdh155122 		if (zone_getattr(zid, ZONE_ATTR_FLAGS, &flags,
9603448Sdh155122 		    sizeof (flags)) < 0) {
9613448Sdh155122 			return (dladm_errno2status(errno));
9623448Sdh155122 		}
9633448Sdh155122 
9643448Sdh155122 		if (!(flags & ZF_NET_EXCL)) {
9653448Sdh155122 			return (DLADM_STATUS_BADVAL);
9663448Sdh155122 		}
9673448Sdh155122 	}
9683448Sdh155122 
9693448Sdh155122 	vdp = malloc(sizeof (val_desc_t));
9703448Sdh155122 	if (vdp == NULL)
9713448Sdh155122 		return (DLADM_STATUS_NOMEM);
9723448Sdh155122 
9733448Sdh155122 	vdp->vd_val = (void *)zid;
9743448Sdh155122 	*vdpp = vdp;
9753448Sdh155122 	return (DLADM_STATUS_OK);
9763448Sdh155122 }
9773448Sdh155122 
9783448Sdh155122 static dladm_status_t
9793448Sdh155122 i_dladm_get_prop_temp(const char *link, dladm_prop_type_t type,
9803448Sdh155122     const char *prop_name, char **prop_val, uint_t *val_cntp)
9813448Sdh155122 {
9823448Sdh155122 	int 		i;
9833448Sdh155122 	dladm_status_t	status;
9843448Sdh155122 	uint_t		cnt;
9853448Sdh155122 	prop_desc_t	*pdp;
9863448Sdh155122 
9873448Sdh155122 	if (link == NULL || prop_name == NULL || prop_val == NULL ||
9883448Sdh155122 	    val_cntp == NULL || *val_cntp == 0)
9893448Sdh155122 		return (DLADM_STATUS_BADARG);
9903448Sdh155122 
9913448Sdh155122 	for (i = 0; i < MAX_PROPS; i++)
9923448Sdh155122 		if (strcasecmp(prop_name, prop_table[i].pd_name) == 0)
9933448Sdh155122 			break;
9943448Sdh155122 
9953448Sdh155122 	if (i == MAX_PROPS)
9963448Sdh155122 		return (DLADM_STATUS_NOTFOUND);
9973448Sdh155122 
9983448Sdh155122 	pdp = &prop_table[i];
9993448Sdh155122 	status = DLADM_STATUS_OK;
10003448Sdh155122 
10013448Sdh155122 	switch (type) {
10023448Sdh155122 	case DLADM_PROP_VAL_CURRENT:
10033448Sdh155122 		status = pdp->pd_get(link, prop_val, val_cntp);
10043448Sdh155122 		break;
10053448Sdh155122 	case DLADM_PROP_VAL_DEFAULT:
10063448Sdh155122 		if (pdp->pd_defval.vd_name == NULL) {
10073448Sdh155122 			status = DLADM_STATUS_NOTSUP;
10083448Sdh155122 			break;
10093448Sdh155122 		}
10103448Sdh155122 		(void) strcpy(*prop_val, pdp->pd_defval.vd_name);
10113448Sdh155122 		*val_cntp = 1;
10123448Sdh155122 		break;
10133448Sdh155122 
10143448Sdh155122 	case DLADM_PROP_VAL_MODIFIABLE:
10153448Sdh155122 		if (pdp->pd_getmod != NULL) {
10163448Sdh155122 			status = pdp->pd_getmod(link, prop_val, val_cntp);
10173448Sdh155122 			break;
10183448Sdh155122 		}
10193448Sdh155122 		cnt = pdp->pd_nmodval;
10203448Sdh155122 		if (cnt == 0) {
10213448Sdh155122 			status = DLADM_STATUS_NOTSUP;
10223448Sdh155122 		} else if (cnt > *val_cntp) {
10233448Sdh155122 			status = DLADM_STATUS_TOOSMALL;
10243448Sdh155122 		} else {
10253448Sdh155122 			for (i = 0; i < cnt; i++) {
10263448Sdh155122 				(void) strcpy(prop_val[i],
10273448Sdh155122 				    pdp->pd_modval[i].vd_name);
10283448Sdh155122 			}
10293448Sdh155122 			*val_cntp = cnt;
10303448Sdh155122 		}
10313448Sdh155122 		break;
10323448Sdh155122 	default:
10333448Sdh155122 		status = DLADM_STATUS_BADARG;
10343448Sdh155122 		break;
10353448Sdh155122 	}
10363448Sdh155122 
10373448Sdh155122 	return (status);
10383448Sdh155122 }
10393448Sdh155122 
10403448Sdh155122 static dladm_status_t
10413448Sdh155122 i_dladm_set_one_prop_temp(const char *link, prop_desc_t *pdp, char **prop_val,
10423448Sdh155122     uint_t val_cnt, uint_t flags)
10433448Sdh155122 {
10443448Sdh155122 	dladm_status_t	status;
10453448Sdh155122 	val_desc_t	*vdp = NULL;
10463448Sdh155122 	uint_t		cnt;
10473448Sdh155122 
10483448Sdh155122 	if (pdp->pd_temponly && (flags & DLADM_OPT_PERSIST) != 0)
10493448Sdh155122 		return (DLADM_STATUS_TEMPONLY);
10503448Sdh155122 
10513448Sdh155122 	if (pdp->pd_set == NULL)
10523448Sdh155122 		return (DLADM_STATUS_PROPRDONLY);
10533448Sdh155122 
10543448Sdh155122 	if (prop_val != NULL) {
10553448Sdh155122 		if (pdp->pd_check != NULL)
10563448Sdh155122 			status = pdp->pd_check(pdp, prop_val, val_cnt, &vdp);
10573448Sdh155122 		else
10583448Sdh155122 			status = DLADM_STATUS_BADARG;
10593448Sdh155122 
10603448Sdh155122 		if (status != DLADM_STATUS_OK)
10613448Sdh155122 			return (status);
10623448Sdh155122 
10633448Sdh155122 		cnt = val_cnt;
10643448Sdh155122 	} else {
10653448Sdh155122 		if (pdp->pd_defval.vd_name == NULL)
10663448Sdh155122 			return (DLADM_STATUS_NOTSUP);
10673448Sdh155122 
10683448Sdh155122 		if ((vdp = malloc(sizeof (val_desc_t))) == NULL)
10693448Sdh155122 			return (DLADM_STATUS_NOMEM);
10703448Sdh155122 
10713448Sdh155122 		(void) memcpy(vdp, &pdp->pd_defval, sizeof (val_desc_t));
10723448Sdh155122 		cnt = 1;
10733448Sdh155122 	}
10743448Sdh155122 
10753448Sdh155122 	status = pdp->pd_set(link, vdp, cnt);
10763448Sdh155122 
10773448Sdh155122 	free(vdp);
10783448Sdh155122 	return (status);
10793448Sdh155122 }
10803448Sdh155122 
10813448Sdh155122 static dladm_status_t
10823448Sdh155122 i_dladm_set_prop_temp(const char *link, const char *prop_name, char **prop_val,
10833448Sdh155122     uint_t val_cnt, uint_t flags, char **errprop)
10843448Sdh155122 {
10853448Sdh155122 	int 		i;
10863448Sdh155122 	dladm_status_t	status = DLADM_STATUS_OK;
10873448Sdh155122 	boolean_t	found = B_FALSE;
10883448Sdh155122 
10893448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
10903448Sdh155122 		prop_desc_t	*pdp = &prop_table[i];
10913448Sdh155122 		dladm_status_t	s;
10923448Sdh155122 
10933448Sdh155122 		if (prop_name != NULL &&
10943448Sdh155122 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
10953448Sdh155122 			continue;
10963448Sdh155122 
10973448Sdh155122 		found = B_TRUE;
10983448Sdh155122 		s = i_dladm_set_one_prop_temp(link, pdp, prop_val, val_cnt,
10993448Sdh155122 		    flags);
11003448Sdh155122 
11013448Sdh155122 		if (prop_name != NULL) {
11023448Sdh155122 			status = s;
11033448Sdh155122 			break;
11043448Sdh155122 		} else {
11053448Sdh155122 			if (s != DLADM_STATUS_OK &&
11063448Sdh155122 			    s != DLADM_STATUS_NOTSUP) {
11073448Sdh155122 				if (errprop != NULL)
11083448Sdh155122 					*errprop = pdp->pd_name;
11093448Sdh155122 				status = s;
11103448Sdh155122 				break;
11113448Sdh155122 			}
11123448Sdh155122 		}
11133448Sdh155122 	}
11143448Sdh155122 
11153448Sdh155122 	if (!found)
11163448Sdh155122 		status = DLADM_STATUS_NOTFOUND;
11173448Sdh155122 
11183448Sdh155122 	return (status);
11193448Sdh155122 }
11203448Sdh155122 
11213448Sdh155122 static boolean_t
11223448Sdh155122 i_dladm_is_prop_temponly(const char *prop_name, char **errprop)
11233448Sdh155122 {
11243448Sdh155122 	int 		i;
11253448Sdh155122 
11263448Sdh155122 	for (i = 0; i < MAX_PROPS; i++) {
11273448Sdh155122 		prop_desc_t	*pdp = &prop_table[i];
11283448Sdh155122 
11293448Sdh155122 		if (prop_name != NULL &&
11303448Sdh155122 		    (strcasecmp(prop_name, pdp->pd_name) != 0))
11313448Sdh155122 			continue;
11323448Sdh155122 
11333448Sdh155122 		if (errprop != NULL)
11343448Sdh155122 			*errprop = pdp->pd_name;
11353448Sdh155122 
11363448Sdh155122 		if (pdp->pd_temponly)
11373448Sdh155122 			return (B_TRUE);
11383448Sdh155122 	}
11393448Sdh155122 
11403448Sdh155122 	return (B_FALSE);
11413448Sdh155122 }
1142