10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229055SMichael.Lim@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <unistd.h>
270Sstevel@tonic-gate #include <errno.h>
285895Syz147064 #include <ctype.h>
293147Sxc151355 #include <fcntl.h>
303147Sxc151355 #include <strings.h>
313147Sxc151355 #include <dirent.h>
328275SEric Cheng #include <stdlib.h>
336173Syz147064 #include <sys/param.h>
343147Sxc151355 #include <sys/stat.h>
358453SAnurag.Maskey@Sun.COM #include <sys/dld.h>
369107Sjames.d.carlson@sun.com #include <sys/dld_ioc.h>
373147Sxc151355 #include <libdladm_impl.h>
383184Smeem #include <libintl.h>
395895Syz147064 #include <libdlpi.h>
40733Skrgopi 
418453SAnurag.Maskey@Sun.COM static char	dladm_rootdir[MAXPATHLEN] = "/";
428453SAnurag.Maskey@Sun.COM 
439815SRishi.Srivatsavai@Sun.COM typedef struct media_type_desc {
449815SRishi.Srivatsavai@Sun.COM 	uint32_t	media_type;
459815SRishi.Srivatsavai@Sun.COM #define	MAX_MEDIA_TYPE_STRING	32
469815SRishi.Srivatsavai@Sun.COM 	const char	media_type_str[MAX_MEDIA_TYPE_STRING];
479815SRishi.Srivatsavai@Sun.COM } media_type_t;
489815SRishi.Srivatsavai@Sun.COM 
499815SRishi.Srivatsavai@Sun.COM static media_type_t media_type_table[] =  {
509815SRishi.Srivatsavai@Sun.COM 	{ DL_ETHER,	"Ethernet" },
519815SRishi.Srivatsavai@Sun.COM 	{ DL_WIFI,	"WiFi" },
529815SRishi.Srivatsavai@Sun.COM 	{ DL_IB,	"Infiniband" },
539815SRishi.Srivatsavai@Sun.COM 	{ DL_IPV4,	"IPv4Tunnel" },
549815SRishi.Srivatsavai@Sun.COM 	{ DL_IPV6,	"IPv6Tunnel" },
55*10616SSebastien.Roy@Sun.COM 	{ DL_6TO4,	"6to4Tunnel" },
569815SRishi.Srivatsavai@Sun.COM 	{ DL_CSMACD,	"CSMA/CD" },
579815SRishi.Srivatsavai@Sun.COM 	{ DL_TPB,	"TokenBus" },
589815SRishi.Srivatsavai@Sun.COM 	{ DL_TPR,	"TokenRing" },
599815SRishi.Srivatsavai@Sun.COM 	{ DL_METRO,	"MetroNet" },
609815SRishi.Srivatsavai@Sun.COM 	{ DL_HDLC,	"HDLC" },
619815SRishi.Srivatsavai@Sun.COM 	{ DL_CHAR,	"SyncCharacter" },
629815SRishi.Srivatsavai@Sun.COM 	{ DL_CTCA,	"CTCA" },
639815SRishi.Srivatsavai@Sun.COM 	{ DL_FDDI, 	"FDDI" },
649815SRishi.Srivatsavai@Sun.COM 	{ DL_FC, 	"FiberChannel" },
659815SRishi.Srivatsavai@Sun.COM 	{ DL_ATM, 	"ATM" },
669815SRishi.Srivatsavai@Sun.COM 	{ DL_IPATM, 	"ATM(ClassicIP)" },
679815SRishi.Srivatsavai@Sun.COM 	{ DL_X25, 	"X.25" },
689815SRishi.Srivatsavai@Sun.COM 	{ DL_IPX25, 	"X.25(ClassicIP)" },
699815SRishi.Srivatsavai@Sun.COM 	{ DL_ISDN, 	"ISDN" },
709815SRishi.Srivatsavai@Sun.COM 	{ DL_HIPPI, 	"HIPPI" },
719815SRishi.Srivatsavai@Sun.COM 	{ DL_100VG, 	"100BaseVGEthernet" },
729815SRishi.Srivatsavai@Sun.COM 	{ DL_100VGTPR, 	"100BaseVGTokenRing" },
739815SRishi.Srivatsavai@Sun.COM 	{ DL_ETH_CSMA, 	"IEEE802.3" },
749815SRishi.Srivatsavai@Sun.COM 	{ DL_100BT, 	"100BaseT" },
759815SRishi.Srivatsavai@Sun.COM 	{ DL_FRAME, 	"FrameRelay" },
769815SRishi.Srivatsavai@Sun.COM 	{ DL_MPFRAME, 	"MPFrameRelay" },
779815SRishi.Srivatsavai@Sun.COM 	{ DL_ASYNC, 	"AsyncCharacter" },
789815SRishi.Srivatsavai@Sun.COM 	{ DL_IPNET, 	"IPNET" },
799815SRishi.Srivatsavai@Sun.COM 	{ DL_OTHER, 	"Other" }
809815SRishi.Srivatsavai@Sun.COM };
819815SRishi.Srivatsavai@Sun.COM #define	MEDIATYPECOUNT	(sizeof (media_type_table) / sizeof (media_type_t))
829815SRishi.Srivatsavai@Sun.COM 
838453SAnurag.Maskey@Sun.COM dladm_status_t
848453SAnurag.Maskey@Sun.COM dladm_open(dladm_handle_t *handle)
858453SAnurag.Maskey@Sun.COM {
868453SAnurag.Maskey@Sun.COM 	int dld_fd;
878453SAnurag.Maskey@Sun.COM 
888453SAnurag.Maskey@Sun.COM 	if (handle == NULL)
898453SAnurag.Maskey@Sun.COM 		return (DLADM_STATUS_BADARG);
908453SAnurag.Maskey@Sun.COM 
918453SAnurag.Maskey@Sun.COM 	if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
928453SAnurag.Maskey@Sun.COM 		return (dladm_errno2status(errno));
938453SAnurag.Maskey@Sun.COM 
948453SAnurag.Maskey@Sun.COM 	/*
958453SAnurag.Maskey@Sun.COM 	 * Don't open DLMGMT_DOOR now.  dlmgmtd(1M) is not able to
968453SAnurag.Maskey@Sun.COM 	 * open the door when the dladm handle is opened because the
978453SAnurag.Maskey@Sun.COM 	 * door hasn't been created yet at that time.  Thus, we must
988453SAnurag.Maskey@Sun.COM 	 * open it on-demand in dladm_door_fd().  Move the open()
998453SAnurag.Maskey@Sun.COM 	 * to dladm_door_fd() for all cases.
1008453SAnurag.Maskey@Sun.COM 	 */
1018453SAnurag.Maskey@Sun.COM 
1028453SAnurag.Maskey@Sun.COM 	if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) {
1038453SAnurag.Maskey@Sun.COM 		(void) close(dld_fd);
1048453SAnurag.Maskey@Sun.COM 		return (DLADM_STATUS_NOMEM);
1058453SAnurag.Maskey@Sun.COM 	}
1068453SAnurag.Maskey@Sun.COM 
1078453SAnurag.Maskey@Sun.COM 	(*handle)->dld_fd = dld_fd;
1088453SAnurag.Maskey@Sun.COM 	(*handle)->door_fd = -1;
1098453SAnurag.Maskey@Sun.COM 
1108453SAnurag.Maskey@Sun.COM 	return (DLADM_STATUS_OK);
1118453SAnurag.Maskey@Sun.COM }
1128453SAnurag.Maskey@Sun.COM 
1138453SAnurag.Maskey@Sun.COM void
1148453SAnurag.Maskey@Sun.COM dladm_close(dladm_handle_t handle)
1158453SAnurag.Maskey@Sun.COM {
1168453SAnurag.Maskey@Sun.COM 	if (handle != NULL) {
1178453SAnurag.Maskey@Sun.COM 		(void) close(handle->dld_fd);
1188453SAnurag.Maskey@Sun.COM 		if (handle->door_fd != -1)
1198453SAnurag.Maskey@Sun.COM 			(void) close(handle->door_fd);
1208453SAnurag.Maskey@Sun.COM 		free(handle);
1218453SAnurag.Maskey@Sun.COM 	}
1228453SAnurag.Maskey@Sun.COM }
1238453SAnurag.Maskey@Sun.COM 
1248453SAnurag.Maskey@Sun.COM int
1258453SAnurag.Maskey@Sun.COM dladm_dld_fd(dladm_handle_t handle)
1268453SAnurag.Maskey@Sun.COM {
1278453SAnurag.Maskey@Sun.COM 	return (handle->dld_fd);
1288453SAnurag.Maskey@Sun.COM }
1298453SAnurag.Maskey@Sun.COM 
1308453SAnurag.Maskey@Sun.COM /*
1318453SAnurag.Maskey@Sun.COM  * If DLMGMT_DOOR hasn't been opened in the handle yet, open it.
1328453SAnurag.Maskey@Sun.COM  */
1338453SAnurag.Maskey@Sun.COM dladm_status_t
1348453SAnurag.Maskey@Sun.COM dladm_door_fd(dladm_handle_t handle, int *door_fd)
1358453SAnurag.Maskey@Sun.COM {
1368453SAnurag.Maskey@Sun.COM 	int fd;
1378453SAnurag.Maskey@Sun.COM 
1388453SAnurag.Maskey@Sun.COM 	if (handle->door_fd == -1) {
1398453SAnurag.Maskey@Sun.COM 		if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0)
1408453SAnurag.Maskey@Sun.COM 			return (dladm_errno2status(errno));
1418453SAnurag.Maskey@Sun.COM 		handle->door_fd = fd;
1428453SAnurag.Maskey@Sun.COM 	}
1438453SAnurag.Maskey@Sun.COM 	*door_fd = handle->door_fd;
1448453SAnurag.Maskey@Sun.COM 
1458453SAnurag.Maskey@Sun.COM 	return (DLADM_STATUS_OK);
1468453SAnurag.Maskey@Sun.COM }
1473147Sxc151355 
1483147Sxc151355 const char *
1493147Sxc151355 dladm_status2str(dladm_status_t status, char *buf)
1503147Sxc151355 {
1513147Sxc151355 	const char	*s;
1523147Sxc151355 
1533147Sxc151355 	switch (status) {
1543147Sxc151355 	case DLADM_STATUS_OK:
1553147Sxc151355 		s = "ok";
1563147Sxc151355 		break;
1573147Sxc151355 	case DLADM_STATUS_BADARG:
1583147Sxc151355 		s = "invalid argument";
1593147Sxc151355 		break;
1603147Sxc151355 	case DLADM_STATUS_FAILED:
1613147Sxc151355 		s = "operation failed";
1623147Sxc151355 		break;
1633147Sxc151355 	case DLADM_STATUS_TOOSMALL:
1643147Sxc151355 		s = "buffer size too small";
1653147Sxc151355 		break;
1663147Sxc151355 	case DLADM_STATUS_NOTSUP:
1673147Sxc151355 		s = "operation not supported";
1683147Sxc151355 		break;
1693147Sxc151355 	case DLADM_STATUS_NOTFOUND:
1703147Sxc151355 		s = "object not found";
1713147Sxc151355 		break;
1723147Sxc151355 	case DLADM_STATUS_BADVAL:
1733147Sxc151355 		s = "invalid value";
1743147Sxc151355 		break;
1753147Sxc151355 	case DLADM_STATUS_NOMEM:
1763147Sxc151355 		s = "insufficient memory";
1773147Sxc151355 		break;
1783147Sxc151355 	case DLADM_STATUS_EXIST:
1793147Sxc151355 		s = "object already exists";
1803147Sxc151355 		break;
1813147Sxc151355 	case DLADM_STATUS_LINKINVAL:
1823147Sxc151355 		s = "invalid link";
1833147Sxc151355 		break;
1843147Sxc151355 	case DLADM_STATUS_PROPRDONLY:
1853147Sxc151355 		s = "read-only property";
1863147Sxc151355 		break;
1873147Sxc151355 	case DLADM_STATUS_BADVALCNT:
1883147Sxc151355 		s = "invalid number of values";
1893147Sxc151355 		break;
1903147Sxc151355 	case DLADM_STATUS_DBNOTFOUND:
1913147Sxc151355 		s = "database not found";
1923147Sxc151355 		break;
1933147Sxc151355 	case DLADM_STATUS_DENIED:
1943147Sxc151355 		s = "permission denied";
1953147Sxc151355 		break;
1963147Sxc151355 	case DLADM_STATUS_IOERR:
1973147Sxc151355 		s = "I/O error";
1983147Sxc151355 		break;
1993448Sdh155122 	case DLADM_STATUS_TEMPONLY:
2008275SEric Cheng 		s = "change cannot be persistent";
2013448Sdh155122 		break;
2023871Syz147064 	case DLADM_STATUS_TIMEDOUT:
2033871Syz147064 		s = "operation timed out";
2043871Syz147064 		break;
2053871Syz147064 	case DLADM_STATUS_ISCONN:
2063871Syz147064 		s = "already connected";
2073871Syz147064 		break;
2083871Syz147064 	case DLADM_STATUS_NOTCONN:
2093871Syz147064 		s = "not connected";
2103871Syz147064 		break;
2113871Syz147064 	case DLADM_STATUS_REPOSITORYINVAL:
2123871Syz147064 		s = "invalid configuration repository";
2133871Syz147064 		break;
2143871Syz147064 	case DLADM_STATUS_MACADDRINVAL:
2153871Syz147064 		s = "invalid MAC address";
2163871Syz147064 		break;
2173871Syz147064 	case DLADM_STATUS_KEYINVAL:
2183871Syz147064 		s = "invalid key";
2193871Syz147064 		break;
2205084Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRLEN:
2215084Sjohnlev 		s = "invalid MAC address length";
2225084Sjohnlev 		break;
2235084Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRTYPE:
2245084Sjohnlev 		s = "invalid MAC address type";
2255084Sjohnlev 		break;
2265895Syz147064 	case DLADM_STATUS_LINKBUSY:
2275895Syz147064 		s = "link busy";
2285895Syz147064 		break;
2295895Syz147064 	case DLADM_STATUS_VIDINVAL:
2305895Syz147064 		s = "invalid VLAN identifier";
2315084Sjohnlev 		break;
2325895Syz147064 	case DLADM_STATUS_TRYAGAIN:
2335895Syz147064 		s = "try again later";
2345084Sjohnlev 		break;
2355895Syz147064 	case DLADM_STATUS_NONOTIF:
2365895Syz147064 		s = "link notification is not supported";
2375084Sjohnlev 		break;
2388275SEric Cheng 	case DLADM_STATUS_BADTIMEVAL:
2398275SEric Cheng 		s = "invalid time range";
2408275SEric Cheng 		break;
2418275SEric Cheng 	case DLADM_STATUS_INVALIDMACADDR:
2428275SEric Cheng 		s = "invalid MAC address value";
2438275SEric Cheng 		break;
2448275SEric Cheng 	case DLADM_STATUS_INVALIDMACADDRNIC:
2458275SEric Cheng 		s = "MAC address reserved for use by underlying data-link";
2468275SEric Cheng 		break;
2478275SEric Cheng 	case DLADM_STATUS_INVALIDMACADDRINUSE:
2488275SEric Cheng 		s = "MAC address is already in use";
2498275SEric Cheng 		break;
2508275SEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTINVALID:
2518275SEric Cheng 		s = "invalid factory MAC address slot";
2528275SEric Cheng 		break;
2538275SEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTUSED:
2548275SEric Cheng 		s = "factory MAC address slot already used";
2558275SEric Cheng 		break;
2568275SEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTALLUSED:
2578275SEric Cheng 		s = "all factory MAC address slots are in use";
2588275SEric Cheng 		break;
2598275SEric Cheng 	case DLADM_STATUS_MACFACTORYNOTSUP:
2608275SEric Cheng 		s = "factory MAC address slots not supported";
2618275SEric Cheng 		break;
2628275SEric Cheng 	case DLADM_STATUS_INVALIDMACPREFIX:
2638275SEric Cheng 		s = "Invalid MAC address prefix value";
2648275SEric Cheng 		break;
2658275SEric Cheng 	case DLADM_STATUS_INVALIDMACPREFIXLEN:
2668275SEric Cheng 		s = "Invalid MAC address prefix length";
2678275SEric Cheng 		break;
2688275SEric Cheng 	case DLADM_STATUS_CPUMAX:
2698275SEric Cheng 		s = "non-existent processor ID";
2708275SEric Cheng 		break;
2718275SEric Cheng 	case DLADM_STATUS_CPUERR:
2728275SEric Cheng 		s = "could not determine processor status";
2738275SEric Cheng 		break;
2748275SEric Cheng 	case DLADM_STATUS_CPUNOTONLINE:
2758275SEric Cheng 		s = "processor not online";
2768275SEric Cheng 		break;
2778275SEric Cheng 	case DLADM_STATUS_DB_NOTFOUND:
2788275SEric Cheng 		s = "database not found";
2798275SEric Cheng 		break;
2808275SEric Cheng 	case DLADM_STATUS_DB_PARSE_ERR:
2818275SEric Cheng 		s = "database parse error";
2828275SEric Cheng 		break;
2838275SEric Cheng 	case DLADM_STATUS_PROP_PARSE_ERR:
2848275SEric Cheng 		s = "property parse error";
2858275SEric Cheng 		break;
2868275SEric Cheng 	case DLADM_STATUS_ATTR_PARSE_ERR:
2878275SEric Cheng 		s = "attribute parse error";
2888275SEric Cheng 		break;
2898275SEric Cheng 	case DLADM_STATUS_FLOW_DB_ERR:
2908275SEric Cheng 		s = "flow database error";
2918275SEric Cheng 		break;
2928275SEric Cheng 	case DLADM_STATUS_FLOW_DB_OPEN_ERR:
2938275SEric Cheng 		s = "flow database open error";
2948275SEric Cheng 		break;
2958275SEric Cheng 	case DLADM_STATUS_FLOW_DB_PARSE_ERR:
2968275SEric Cheng 		s = "flow database parse error";
2978275SEric Cheng 		break;
2988275SEric Cheng 	case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR:
2998275SEric Cheng 		s = "flow property database parse error";
3008275SEric Cheng 		break;
3018275SEric Cheng 	case DLADM_STATUS_FLOW_ADD_ERR:
3028275SEric Cheng 		s = "flow add error";
3038275SEric Cheng 		break;
3048275SEric Cheng 	case DLADM_STATUS_FLOW_WALK_ERR:
3058275SEric Cheng 		s = "flow walk error";
3068275SEric Cheng 		break;
3078275SEric Cheng 	case DLADM_STATUS_FLOW_IDENTICAL:
3088275SEric Cheng 		s = "a flow with identical attributes exists";
3098275SEric Cheng 		break;
3108275SEric Cheng 	case DLADM_STATUS_FLOW_INCOMPATIBLE:
3118275SEric Cheng 		s = "flow(s) with incompatible attributes exists";
3128275SEric Cheng 		break;
3138275SEric Cheng 	case DLADM_STATUS_FLOW_EXISTS:
3148275SEric Cheng 		s = "link still has flows";
3158275SEric Cheng 		break;
3168275SEric Cheng 	case DLADM_STATUS_PERSIST_FLOW_EXISTS:
3178275SEric Cheng 		s = "persistent flow with the same name exists";
3188275SEric Cheng 		break;
3198275SEric Cheng 	case DLADM_STATUS_INVALID_IP:
3208275SEric Cheng 		s = "invalid IP address";
3218275SEric Cheng 		break;
3228275SEric Cheng 	case DLADM_STATUS_INVALID_PREFIXLEN:
3238275SEric Cheng 		s = "invalid IP prefix length";
3248275SEric Cheng 		break;
3258275SEric Cheng 	case DLADM_STATUS_INVALID_PROTOCOL:
3268275SEric Cheng 		s = "invalid IP protocol";
3278275SEric Cheng 		break;
3288275SEric Cheng 	case DLADM_STATUS_INVALID_PORT:
3298275SEric Cheng 		s = "invalid port number";
3308275SEric Cheng 		break;
3318275SEric Cheng 	case DLADM_STATUS_INVALID_DSF:
3328275SEric Cheng 		s = "invalid dsfield";
3338275SEric Cheng 		break;
3348275SEric Cheng 	case DLADM_STATUS_INVALID_DSFMASK:
3358275SEric Cheng 		s = "invalid dsfield mask";
3368275SEric Cheng 		break;
3378275SEric Cheng 	case DLADM_STATUS_INVALID_MACMARGIN:
3388275SEric Cheng 		s = "MTU check failed, use lower MTU or -f option";
3398275SEric Cheng 		break;
3408275SEric Cheng 	case DLADM_STATUS_BADPROP:
3418275SEric Cheng 		s = "invalid property";
3428275SEric Cheng 		break;
3438275SEric Cheng 	case DLADM_STATUS_MINMAXBW:
3448275SEric Cheng 		s = "minimum value for maxbw is 1.2M";
3458275SEric Cheng 		break;
3468275SEric Cheng 	case DLADM_STATUS_NO_HWRINGS:
3478275SEric Cheng 		s = "request hw rings failed";
3488275SEric Cheng 		break;
34910491SRishi.Srivatsavai@Sun.COM 	case DLADM_STATUS_PERMONLY:
35010491SRishi.Srivatsavai@Sun.COM 		s = "change must be persistent";
35110491SRishi.Srivatsavai@Sun.COM 		break;
35210491SRishi.Srivatsavai@Sun.COM 	case DLADM_STATUS_OPTMISSING:
35310491SRishi.Srivatsavai@Sun.COM 		s = "optional software not installed";
35410491SRishi.Srivatsavai@Sun.COM 		break;
355*10616SSebastien.Roy@Sun.COM 	case DLADM_STATUS_IPTUNTYPE:
356*10616SSebastien.Roy@Sun.COM 		s = "invalid IP tunnel type";
357*10616SSebastien.Roy@Sun.COM 		break;
358*10616SSebastien.Roy@Sun.COM 	case DLADM_STATUS_IPTUNTYPEREQD:
359*10616SSebastien.Roy@Sun.COM 		s = "IP tunnel type required";
360*10616SSebastien.Roy@Sun.COM 		break;
361*10616SSebastien.Roy@Sun.COM 	case DLADM_STATUS_BADIPTUNLADDR:
362*10616SSebastien.Roy@Sun.COM 		s = "invalid local IP tunnel address";
363*10616SSebastien.Roy@Sun.COM 		break;
364*10616SSebastien.Roy@Sun.COM 	case DLADM_STATUS_BADIPTUNRADDR:
365*10616SSebastien.Roy@Sun.COM 		s = "invalid remote IP tunnel address";
366*10616SSebastien.Roy@Sun.COM 		break;
367*10616SSebastien.Roy@Sun.COM 	case DLADM_STATUS_ADDRINUSE:
368*10616SSebastien.Roy@Sun.COM 		s = "address already in use";
369*10616SSebastien.Roy@Sun.COM 		break;
3703147Sxc151355 	default:
3713184Smeem 		s = "<unknown error>";
3723184Smeem 		break;
3733147Sxc151355 	}
3743184Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
3753147Sxc151355 	return (buf);
3763147Sxc151355 }
3773147Sxc151355 
3783147Sxc151355 /*
3793147Sxc151355  * Convert a unix errno to a dladm_status_t.
3803147Sxc151355  * We only convert errnos that are likely to be encountered. All others
3813147Sxc151355  * are mapped to DLADM_STATUS_FAILED.
3823147Sxc151355  */
3833147Sxc151355 dladm_status_t
3843147Sxc151355 dladm_errno2status(int err)
3853147Sxc151355 {
3863147Sxc151355 	switch (err) {
3875903Ssowmini 	case 0:
3885903Ssowmini 		return (DLADM_STATUS_OK);
3893147Sxc151355 	case EINVAL:
3903147Sxc151355 		return (DLADM_STATUS_BADARG);
3913147Sxc151355 	case EEXIST:
3923147Sxc151355 		return (DLADM_STATUS_EXIST);
3933147Sxc151355 	case ENOENT:
3943147Sxc151355 		return (DLADM_STATUS_NOTFOUND);
3953147Sxc151355 	case ENOSPC:
3963147Sxc151355 		return (DLADM_STATUS_TOOSMALL);
3973147Sxc151355 	case ENOMEM:
3983147Sxc151355 		return (DLADM_STATUS_NOMEM);
3993147Sxc151355 	case ENOTSUP:
4003147Sxc151355 		return (DLADM_STATUS_NOTSUP);
4015895Syz147064 	case ENETDOWN:
4025895Syz147064 		return (DLADM_STATUS_NONOTIF);
4033147Sxc151355 	case EACCES:
4047408SSebastien.Roy@Sun.COM 	case EPERM:
4053147Sxc151355 		return (DLADM_STATUS_DENIED);
4063147Sxc151355 	case EIO:
4073147Sxc151355 		return (DLADM_STATUS_IOERR);
4085084Sjohnlev 	case EBUSY:
4095895Syz147064 		return (DLADM_STATUS_LINKBUSY);
4105895Syz147064 	case EAGAIN:
4115895Syz147064 		return (DLADM_STATUS_TRYAGAIN);
4128275SEric Cheng 	case ENOTEMPTY:
4138275SEric Cheng 		return (DLADM_STATUS_FLOW_EXISTS);
4148275SEric Cheng 	case EOPNOTSUPP:
4158275SEric Cheng 		return (DLADM_STATUS_FLOW_INCOMPATIBLE);
4168275SEric Cheng 	case EALREADY:
4178275SEric Cheng 		return (DLADM_STATUS_FLOW_IDENTICAL);
418*10616SSebastien.Roy@Sun.COM 	case EADDRINUSE:
419*10616SSebastien.Roy@Sun.COM 		return (DLADM_STATUS_ADDRINUSE);
4203147Sxc151355 	default:
4213147Sxc151355 		return (DLADM_STATUS_FAILED);
4223147Sxc151355 	}
4233147Sxc151355 }
4243147Sxc151355 
4259055SMichael.Lim@Sun.COM boolean_t
4269055SMichael.Lim@Sun.COM dladm_str2interval(char *oarg, uint32_t *interval)
4279055SMichael.Lim@Sun.COM {
4289055SMichael.Lim@Sun.COM 	int		val;
4299055SMichael.Lim@Sun.COM 	char		*endp = NULL;
4309055SMichael.Lim@Sun.COM 
4319055SMichael.Lim@Sun.COM 	errno = 0;
4329055SMichael.Lim@Sun.COM 	val = strtol(oarg, &endp, 10);
4339055SMichael.Lim@Sun.COM 	if (errno != 0 || val <= 0 || *endp != '\0')
4349055SMichael.Lim@Sun.COM 		return (B_FALSE);
4359055SMichael.Lim@Sun.COM 
4369055SMichael.Lim@Sun.COM 	*interval = val;
4379055SMichael.Lim@Sun.COM 
4389055SMichael.Lim@Sun.COM 	return (B_TRUE);
4399055SMichael.Lim@Sun.COM }
4409055SMichael.Lim@Sun.COM 
4418275SEric Cheng dladm_status_t
4428275SEric Cheng dladm_str2bw(char *oarg, uint64_t *bw)
4438275SEric Cheng {
4448275SEric Cheng 	char		*endp = NULL;
4458275SEric Cheng 	int64_t		n;
4468275SEric Cheng 	int		mult = 1;
4478275SEric Cheng 
4488275SEric Cheng 	n = strtoull(oarg, &endp, 10);
4498275SEric Cheng 
4508275SEric Cheng 	if ((errno != 0) || (strlen(endp) > 1))
4518275SEric Cheng 		return (DLADM_STATUS_BADARG);
4528275SEric Cheng 
4538275SEric Cheng 	if (n < 0)
4548275SEric Cheng 		return (DLADM_STATUS_BADVAL);
4558275SEric Cheng 
4568275SEric Cheng 	switch (*endp) {
4578275SEric Cheng 	case 'k':
4588275SEric Cheng 	case 'K':
4598275SEric Cheng 		mult = 1000;
4608275SEric Cheng 		break;
4618275SEric Cheng 	case 'm':
4628275SEric Cheng 	case 'M':
4638275SEric Cheng 	case '\0':
4648275SEric Cheng 		mult = 1000000;
4658275SEric Cheng 		break;
4668275SEric Cheng 	case 'g':
4678275SEric Cheng 	case 'G':
4688275SEric Cheng 		mult = 1000000000;
4698275SEric Cheng 		break;
4708275SEric Cheng 	case '%':
4718275SEric Cheng 		/*
4728275SEric Cheng 		 * percentages not supported for now,
4738275SEric Cheng 		 * see RFE 6540675
4748275SEric Cheng 		 */
4758275SEric Cheng 		return (DLADM_STATUS_NOTSUP);
4768275SEric Cheng 	default:
4778275SEric Cheng 		return (DLADM_STATUS_BADVAL);
4788275SEric Cheng 	}
4798275SEric Cheng 
4808275SEric Cheng 	*bw = n * mult;
4818275SEric Cheng 
4828275SEric Cheng 	/* check for overflow */
4838275SEric Cheng 	if (*bw / mult != n)
4848275SEric Cheng 		return (DLADM_STATUS_BADARG);
4858275SEric Cheng 
4868275SEric Cheng 	return (DLADM_STATUS_OK);
4878275SEric Cheng }
4888275SEric Cheng 
4898275SEric Cheng /*
4908275SEric Cheng  * Convert bandwidth in bps to a string in mpbs.  For values greater
4918275SEric Cheng  * than 1mbps or 1000000, print a whole mbps value.  For values that
4928275SEric Cheng  * have fractional Mbps in whole Kbps , print the bandwidth in a manner
4938275SEric Cheng  * simlilar to a floating point format.
4948275SEric Cheng  *
4958275SEric Cheng  *        bps       string
4968275SEric Cheng  *          0            0
4978275SEric Cheng  *        100            0
4988275SEric Cheng  *       2000        0.002
4998275SEric Cheng  *     431000        0.431
5008275SEric Cheng  *    1000000            1
5018275SEric Cheng  *    1030000        1.030
5028275SEric Cheng  *  100000000          100
5038275SEric Cheng  */
5048275SEric Cheng const char *
5058275SEric Cheng dladm_bw2str(int64_t bw, char *buf)
5068275SEric Cheng {
5078275SEric Cheng 	int kbps, mbps;
5088275SEric Cheng 
5098275SEric Cheng 	kbps = (bw%1000000)/1000;
5108275SEric Cheng 	mbps = bw/1000000;
5118275SEric Cheng 	if (kbps != 0) {
5128275SEric Cheng 		if (mbps == 0)
5138275SEric Cheng 			(void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps);
5148275SEric Cheng 		else
5158275SEric Cheng 			(void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps,
5168275SEric Cheng 			    kbps);
5178275SEric Cheng 	} else {
5188275SEric Cheng 		(void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps);
5198275SEric Cheng 	}
5208275SEric Cheng 
5218275SEric Cheng 	return (buf);
5228275SEric Cheng }
5238275SEric Cheng 
5245895Syz147064 #define	LOCK_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
5253147Sxc151355 
5263147Sxc151355 static int
5273147Sxc151355 i_dladm_lock_db(const char *lock_file, short type)
5283147Sxc151355 {
5293147Sxc151355 	int	lock_fd;
5305895Syz147064 	struct	flock lock;
5313147Sxc151355 
5323147Sxc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
5333147Sxc151355 	    LOCK_DB_PERMS)) < 0)
5343147Sxc151355 		return (-1);
5353147Sxc151355 
5363147Sxc151355 	lock.l_type = type;
5373147Sxc151355 	lock.l_whence = SEEK_SET;
5383147Sxc151355 	lock.l_start = 0;
5393147Sxc151355 	lock.l_len = 0;
5403147Sxc151355 
5413147Sxc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
5423147Sxc151355 		int err = errno;
5433147Sxc151355 
5443147Sxc151355 		(void) close(lock_fd);
5453147Sxc151355 		(void) unlink(lock_file);
5463147Sxc151355 		errno = err;
5473147Sxc151355 		return (-1);
5483147Sxc151355 	}
5493147Sxc151355 	return (lock_fd);
5503147Sxc151355 }
5513147Sxc151355 
5523147Sxc151355 static void
5533147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd)
5543147Sxc151355 {
5553147Sxc151355 	struct flock lock;
5563147Sxc151355 
5573147Sxc151355 	if (fd < 0)
5583147Sxc151355 		return;
5593147Sxc151355 
5603147Sxc151355 	lock.l_type = F_UNLCK;
5613147Sxc151355 	lock.l_whence = SEEK_SET;
5623147Sxc151355 	lock.l_start = 0;
5633147Sxc151355 	lock.l_len = 0;
5643147Sxc151355 
5653147Sxc151355 	(void) fcntl(fd, F_SETLKW, &lock);
5663147Sxc151355 	(void) close(fd);
5673147Sxc151355 	(void) unlink(lock_file);
5683147Sxc151355 }
5693147Sxc151355 
5705895Syz147064 /*
5715895Syz147064  * Given a link class, returns its class string.
5725895Syz147064  */
5735895Syz147064 const char *
5745895Syz147064 dladm_class2str(datalink_class_t class, char *buf)
5755895Syz147064 {
5765895Syz147064 	const char *s;
5775895Syz147064 
5785895Syz147064 	switch (class) {
5795895Syz147064 	case DATALINK_CLASS_PHYS:
5805895Syz147064 		s = "phys";
5815895Syz147064 		break;
5825895Syz147064 	case DATALINK_CLASS_VLAN:
5835895Syz147064 		s = "vlan";
5845895Syz147064 		break;
5855895Syz147064 	case DATALINK_CLASS_AGGR:
5865895Syz147064 		s = "aggr";
5875895Syz147064 		break;
5885895Syz147064 	case DATALINK_CLASS_VNIC:
5895895Syz147064 		s = "vnic";
5905895Syz147064 		break;
5918275SEric Cheng 	case DATALINK_CLASS_ETHERSTUB:
5928275SEric Cheng 		s = "etherstub";
5938275SEric Cheng 		break;
594*10616SSebastien.Roy@Sun.COM 	case DATALINK_CLASS_IPTUN:
595*10616SSebastien.Roy@Sun.COM 		s = "iptun";
596*10616SSebastien.Roy@Sun.COM 		break;
5979815SRishi.Srivatsavai@Sun.COM 	case DATALINK_CLASS_SIMNET:
5989815SRishi.Srivatsavai@Sun.COM 		s = "simnet";
5999815SRishi.Srivatsavai@Sun.COM 		break;
60010491SRishi.Srivatsavai@Sun.COM 	case DATALINK_CLASS_BRIDGE:
60110491SRishi.Srivatsavai@Sun.COM 		s = "bridge";
60210491SRishi.Srivatsavai@Sun.COM 		break;
6035895Syz147064 	default:
6045895Syz147064 		s = "unknown";
6055895Syz147064 		break;
6065895Syz147064 	}
6075895Syz147064 
6085895Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
6095895Syz147064 	return (buf);
6105895Syz147064 }
6115895Syz147064 
6125895Syz147064 /*
6135895Syz147064  * Given a physical link media type, returns its media type string.
6145895Syz147064  */
6155895Syz147064 const char *
6165895Syz147064 dladm_media2str(uint32_t media, char *buf)
6175895Syz147064 {
6189815SRishi.Srivatsavai@Sun.COM 	const char *s = "--";
6199815SRishi.Srivatsavai@Sun.COM 	media_type_t *mt;
6209815SRishi.Srivatsavai@Sun.COM 	int idx;
6215895Syz147064 
6229815SRishi.Srivatsavai@Sun.COM 	for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
6239815SRishi.Srivatsavai@Sun.COM 		mt = media_type_table + idx;
6249815SRishi.Srivatsavai@Sun.COM 		if (mt->media_type == media) {
6259815SRishi.Srivatsavai@Sun.COM 			s = mt->media_type_str;
6269815SRishi.Srivatsavai@Sun.COM 			break;
6279815SRishi.Srivatsavai@Sun.COM 		}
6285895Syz147064 	}
6295895Syz147064 
6305895Syz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
6315895Syz147064 	return (buf);
6325895Syz147064 }
6335895Syz147064 
6349815SRishi.Srivatsavai@Sun.COM /*
6359815SRishi.Srivatsavai@Sun.COM  * Given a physical link media type string, returns its media type constant.
6369815SRishi.Srivatsavai@Sun.COM  */
6379815SRishi.Srivatsavai@Sun.COM uint32_t
6389815SRishi.Srivatsavai@Sun.COM dladm_str2media(const char *buf)
6399815SRishi.Srivatsavai@Sun.COM {
6409815SRishi.Srivatsavai@Sun.COM 	media_type_t *mt;
6419815SRishi.Srivatsavai@Sun.COM 	int idx;
6429815SRishi.Srivatsavai@Sun.COM 
6439815SRishi.Srivatsavai@Sun.COM 	for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
6449815SRishi.Srivatsavai@Sun.COM 		mt = media_type_table + idx;
6459815SRishi.Srivatsavai@Sun.COM 		if (strcasecmp(buf, mt->media_type_str) == 0)
6469815SRishi.Srivatsavai@Sun.COM 			return (mt->media_type);
6479815SRishi.Srivatsavai@Sun.COM 	}
6489815SRishi.Srivatsavai@Sun.COM 
6499815SRishi.Srivatsavai@Sun.COM 	return (DL_OTHER);
6509815SRishi.Srivatsavai@Sun.COM }
6519815SRishi.Srivatsavai@Sun.COM 
6523147Sxc151355 dladm_status_t
6538453SAnurag.Maskey@Sun.COM i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms,
6548453SAnurag.Maskey@Sun.COM     dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *),
6553147Sxc151355     void *arg, boolean_t writeop)
6563147Sxc151355 {
6573147Sxc151355 	dladm_status_t	status = DLADM_STATUS_OK;
6583147Sxc151355 	FILE		*fp, *nfp = NULL;
6593147Sxc151355 	char		lock[MAXPATHLEN];
6603147Sxc151355 	char		file[MAXPATHLEN];
6613147Sxc151355 	char		newfile[MAXPATHLEN];
6623147Sxc151355 	char		*db_basename;
6633147Sxc151355 	int		nfd, lock_fd;
6643147Sxc151355 
6653147Sxc151355 	/*
6663147Sxc151355 	 * If we are called from a boot script such as net-physical,
6673147Sxc151355 	 * it's quite likely that the root fs is still not writable.
6683147Sxc151355 	 * For this case, it's ok for the lock creation to fail since
6693147Sxc151355 	 * no one else could be accessing our configuration file.
6703147Sxc151355 	 */
6713147Sxc151355 	db_basename = strrchr(db_file, '/');
6723147Sxc151355 	if (db_basename == NULL || db_basename[1] == '\0')
6733147Sxc151355 		return (dladm_errno2status(EINVAL));
6743147Sxc151355 	db_basename++;
6753147Sxc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
6763147Sxc151355 	if ((lock_fd = i_dladm_lock_db
6773147Sxc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
6783147Sxc151355 		return (dladm_errno2status(errno));
6793147Sxc151355 
6803147Sxc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
6813147Sxc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
6823147Sxc151355 		int	err = errno;
6833147Sxc151355 
6843147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
6853147Sxc151355 		if (err == ENOENT)
6863147Sxc151355 			return (DLADM_STATUS_DBNOTFOUND);
6873147Sxc151355 
6883147Sxc151355 		return (dladm_errno2status(err));
6893147Sxc151355 	}
6903147Sxc151355 
6913147Sxc151355 	if (writeop) {
6923147Sxc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
6933147Sxc151355 		    dladm_rootdir, db_file);
6943147Sxc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
6953147Sxc151355 		    db_perms)) < 0) {
6963147Sxc151355 			(void) fclose(fp);
6973147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
6983147Sxc151355 			return (dladm_errno2status(errno));
6993147Sxc151355 		}
7003147Sxc151355 
7013147Sxc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
7023147Sxc151355 			(void) close(nfd);
7033147Sxc151355 			(void) fclose(fp);
7043147Sxc151355 			(void) unlink(newfile);
7053147Sxc151355 			i_dladm_unlock_db(lock, lock_fd);
7063147Sxc151355 			return (dladm_errno2status(errno));
7073147Sxc151355 		}
7083147Sxc151355 	}
7098453SAnurag.Maskey@Sun.COM 	status = (*process_db)(handle, arg, fp, nfp);
7103147Sxc151355 	if (!writeop || status != DLADM_STATUS_OK)
7113147Sxc151355 		goto done;
7123147Sxc151355 
7133147Sxc151355 	/*
7143147Sxc151355 	 * Configuration files need to be owned by the 'dladm' user.
7153147Sxc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
7163147Sxc151355 	 */
7173147Sxc151355 	if (getuid() == 0 || geteuid() == 0) {
7186173Syz147064 		if (fchown(nfd, UID_DLADM, GID_SYS) < 0) {
7193147Sxc151355 			status = dladm_errno2status(errno);
7203147Sxc151355 			goto done;
7213147Sxc151355 		}
7223147Sxc151355 	}
7233147Sxc151355 
7243147Sxc151355 	if (fflush(nfp) == EOF) {
7253147Sxc151355 		status = dladm_errno2status(errno);
7263147Sxc151355 		goto done;
7273147Sxc151355 	}
7283147Sxc151355 	(void) fclose(fp);
7293147Sxc151355 	(void) fclose(nfp);
7303147Sxc151355 
7313147Sxc151355 	if (rename(newfile, file) < 0) {
7323147Sxc151355 		(void) unlink(newfile);
7333147Sxc151355 		i_dladm_unlock_db(lock, lock_fd);
7343147Sxc151355 		return (dladm_errno2status(errno));
7353147Sxc151355 	}
7363147Sxc151355 
7373147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
7383147Sxc151355 	return (DLADM_STATUS_OK);
7393147Sxc151355 
7403147Sxc151355 done:
7413147Sxc151355 	if (nfp != NULL) {
7423147Sxc151355 		(void) fclose(nfp);
7433147Sxc151355 		if (status != DLADM_STATUS_OK)
7443147Sxc151355 			(void) unlink(newfile);
7453147Sxc151355 	}
7463147Sxc151355 	(void) fclose(fp);
7473147Sxc151355 	i_dladm_unlock_db(lock, lock_fd);
7483147Sxc151355 	return (status);
7493147Sxc151355 }
7503147Sxc151355 
7513147Sxc151355 dladm_status_t
7523147Sxc151355 dladm_set_rootdir(const char *rootdir)
7533147Sxc151355 {
7543147Sxc151355 	DIR	*dp;
7553147Sxc151355 
7563147Sxc151355 	if (rootdir == NULL || *rootdir != '/' ||
7573147Sxc151355 	    (dp = opendir(rootdir)) == NULL)
7583147Sxc151355 		return (DLADM_STATUS_BADARG);
7593147Sxc151355 
7603147Sxc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
7613147Sxc151355 	(void) closedir(dp);
7623147Sxc151355 	return (DLADM_STATUS_OK);
7633147Sxc151355 }
7645895Syz147064 
7655895Syz147064 boolean_t
7665895Syz147064 dladm_valid_linkname(const char *link)
7675895Syz147064 {
7685895Syz147064 	size_t		len = strlen(link);
7695895Syz147064 	const char	*cp;
7705895Syz147064 
771*10616SSebastien.Roy@Sun.COM 	if (len >= MAXLINKNAMELEN)
7725895Syz147064 		return (B_FALSE);
7735895Syz147064 
7745895Syz147064 	/*
7755895Syz147064 	 * The link name cannot start with a digit and must end with a digit.
7765895Syz147064 	 */
7775895Syz147064 	if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0))
7785895Syz147064 		return (B_FALSE);
7795895Syz147064 
7805895Syz147064 	/*
7815895Syz147064 	 * The legal characters in a link name are:
782*10616SSebastien.Roy@Sun.COM 	 * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
7835895Syz147064 	 */
7845895Syz147064 	for (cp = link; *cp != '\0'; cp++) {
785*10616SSebastien.Roy@Sun.COM 		if ((isalnum(*cp) == 0) && (*cp != '_') && (*cp != '.'))
7865895Syz147064 			return (B_FALSE);
7875895Syz147064 	}
7885895Syz147064 
7895895Syz147064 	return (B_TRUE);
7905895Syz147064 }
7918275SEric Cheng 
7928275SEric Cheng /*
7938275SEric Cheng  * Convert priority string to a value.
7948275SEric Cheng  */
7958275SEric Cheng dladm_status_t
7968275SEric Cheng dladm_str2pri(char *token, mac_priority_level_t *pri)
7978275SEric Cheng {
7988275SEric Cheng 	if (strlen(token) == strlen("low") &&
7998275SEric Cheng 	    strncasecmp(token, "low", strlen("low")) == 0) {
8008275SEric Cheng 		*pri = MPL_LOW;
8018275SEric Cheng 	} else if (strlen(token) == strlen("medium") &&
8028275SEric Cheng 	    strncasecmp(token, "medium", strlen("medium")) == 0) {
8038275SEric Cheng 		*pri = MPL_MEDIUM;
8048275SEric Cheng 	} else if (strlen(token) == strlen("high") &&
8058275SEric Cheng 	    strncasecmp(token, "high", strlen("high")) == 0) {
8068275SEric Cheng 		*pri = MPL_HIGH;
8078275SEric Cheng 	} else {
8088275SEric Cheng 		return (DLADM_STATUS_BADVAL);
8098275SEric Cheng 	}
8108275SEric Cheng 	return (DLADM_STATUS_OK);
8118275SEric Cheng }
8128275SEric Cheng 
8138275SEric Cheng /*
8148275SEric Cheng  * Convert priority value to a string.
8158275SEric Cheng  */
8168275SEric Cheng const char *
8178275SEric Cheng dladm_pri2str(mac_priority_level_t pri, char *buf)
8188275SEric Cheng {
8198275SEric Cheng 	const char	*s;
8208275SEric Cheng 
8218275SEric Cheng 	switch (pri) {
8228275SEric Cheng 	case MPL_LOW:
8238275SEric Cheng 		s = "low";
8248275SEric Cheng 		break;
8258275SEric Cheng 	case MPL_MEDIUM:
8268275SEric Cheng 		s = "medium";
8278275SEric Cheng 		break;
8288275SEric Cheng 	case MPL_HIGH:
8298275SEric Cheng 		s = "high";
8308275SEric Cheng 		break;
8318275SEric Cheng 	default:
8328275SEric Cheng 		s = "--";
8338275SEric Cheng 		break;
8348275SEric Cheng 	}
8358275SEric Cheng 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
8368275SEric Cheng 	return (buf);
8378275SEric Cheng }
8388275SEric Cheng 
8398275SEric Cheng void
8408275SEric Cheng dladm_free_args(dladm_arg_list_t *list)
8418275SEric Cheng {
8428275SEric Cheng 	if (list != NULL) {
8438275SEric Cheng 		free(list->al_buf);
8448275SEric Cheng 		free(list);
8458275SEric Cheng 	}
8468275SEric Cheng }
8478275SEric Cheng 
8488275SEric Cheng dladm_status_t
8498275SEric Cheng dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues)
8508275SEric Cheng {
8518275SEric Cheng 	dladm_arg_list_t	*list;
8528275SEric Cheng 	dladm_arg_info_t	*aip;
8538275SEric Cheng 	char			*buf, *curr;
8548275SEric Cheng 	int			len, i;
8558275SEric Cheng 
8569055SMichael.Lim@Sun.COM 	if (str == NULL)
8579055SMichael.Lim@Sun.COM 		return (DLADM_STATUS_BADVAL);
8589055SMichael.Lim@Sun.COM 
8599055SMichael.Lim@Sun.COM 	if (str[0] == '\0')
8609055SMichael.Lim@Sun.COM 		return (DLADM_STATUS_OK);
8619055SMichael.Lim@Sun.COM 
8628275SEric Cheng 	list = malloc(sizeof (dladm_arg_list_t));
8638275SEric Cheng 	if (list == NULL)
8648275SEric Cheng 		return (dladm_errno2status(errno));
8658275SEric Cheng 
8668275SEric Cheng 	list->al_count = 0;
8678275SEric Cheng 	list->al_buf = buf = strdup(str);
8688275SEric Cheng 	if (buf == NULL)
8698275SEric Cheng 		return (dladm_errno2status(errno));
8708275SEric Cheng 
8718275SEric Cheng 	curr = buf;
8728275SEric Cheng 	len = strlen(buf);
8738275SEric Cheng 	aip = NULL;
8748275SEric Cheng 	for (i = 0; i < len; i++) {
8758275SEric Cheng 		char		c = buf[i];
8768275SEric Cheng 		boolean_t	match = (c == '=' || c == ',');
8778275SEric Cheng 
8788275SEric Cheng 		if (!match && i != len - 1)
8798275SEric Cheng 			continue;
8808275SEric Cheng 
8818275SEric Cheng 		if (match) {
8828275SEric Cheng 			buf[i] = '\0';
8838275SEric Cheng 			if (*curr == '\0')
8848275SEric Cheng 				goto fail;
8858275SEric Cheng 		}
8868275SEric Cheng 
8878275SEric Cheng 		if (aip != NULL && c != '=') {
8888275SEric Cheng 			if (aip->ai_count > DLADM_MAX_ARG_VALS)
8898275SEric Cheng 				goto fail;
8908275SEric Cheng 
8918275SEric Cheng 			if (novalues)
8928275SEric Cheng 				goto fail;
8938275SEric Cheng 
8948275SEric Cheng 			aip->ai_val[aip->ai_count] = curr;
8958275SEric Cheng 			aip->ai_count++;
8968275SEric Cheng 		} else {
8978275SEric Cheng 			if (list->al_count > DLADM_MAX_ARG_VALS)
8988275SEric Cheng 				goto fail;
8998275SEric Cheng 
9008275SEric Cheng 			aip = &list->al_info[list->al_count];
9018275SEric Cheng 			aip->ai_name = curr;
9028275SEric Cheng 			aip->ai_count = 0;
9038275SEric Cheng 			list->al_count++;
9048275SEric Cheng 			if (c == ',')
9058275SEric Cheng 				aip = NULL;
9068275SEric Cheng 		}
9078275SEric Cheng 		curr = buf + i + 1;
9088275SEric Cheng 	}
9098275SEric Cheng 
9108275SEric Cheng 	*listp = list;
9118275SEric Cheng 	return (DLADM_STATUS_OK);
9128275SEric Cheng 
9138275SEric Cheng fail:
9148275SEric Cheng 	dladm_free_args(list);
9158275SEric Cheng 	return (DLADM_STATUS_FAILED);
9168275SEric Cheng }
917