17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d62bc4baSyz  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <unistd.h>
277c478bd9Sstevel@tonic-gate #include <errno.h>
28d62bc4baSyz #include <ctype.h>
290ba2cbe9Sxc #include <fcntl.h>
300ba2cbe9Sxc #include <strings.h>
310ba2cbe9Sxc #include <dirent.h>
32*da14cebeSEric Cheng #include <stdlib.h>
33b9e076dcSyz #include <sys/param.h>
340ba2cbe9Sxc #include <sys/stat.h>
350ba2cbe9Sxc #include <libdladm_impl.h>
3633343a97Smeem #include <libintl.h>
37d62bc4baSyz #include <libdlpi.h>
38aae21359Skrgopi 
390ba2cbe9Sxc static char		dladm_rootdir[MAXPATHLEN] = "/";
400ba2cbe9Sxc 
410ba2cbe9Sxc const char *
420ba2cbe9Sxc dladm_status2str(dladm_status_t status, char *buf)
430ba2cbe9Sxc {
440ba2cbe9Sxc 	const char	*s;
450ba2cbe9Sxc 
460ba2cbe9Sxc 	switch (status) {
470ba2cbe9Sxc 	case DLADM_STATUS_OK:
480ba2cbe9Sxc 		s = "ok";
490ba2cbe9Sxc 		break;
500ba2cbe9Sxc 	case DLADM_STATUS_BADARG:
510ba2cbe9Sxc 		s = "invalid argument";
520ba2cbe9Sxc 		break;
530ba2cbe9Sxc 	case DLADM_STATUS_FAILED:
540ba2cbe9Sxc 		s = "operation failed";
550ba2cbe9Sxc 		break;
560ba2cbe9Sxc 	case DLADM_STATUS_TOOSMALL:
570ba2cbe9Sxc 		s = "buffer size too small";
580ba2cbe9Sxc 		break;
590ba2cbe9Sxc 	case DLADM_STATUS_NOTSUP:
600ba2cbe9Sxc 		s = "operation not supported";
610ba2cbe9Sxc 		break;
620ba2cbe9Sxc 	case DLADM_STATUS_NOTFOUND:
630ba2cbe9Sxc 		s = "object not found";
640ba2cbe9Sxc 		break;
650ba2cbe9Sxc 	case DLADM_STATUS_BADVAL:
660ba2cbe9Sxc 		s = "invalid value";
670ba2cbe9Sxc 		break;
680ba2cbe9Sxc 	case DLADM_STATUS_NOMEM:
690ba2cbe9Sxc 		s = "insufficient memory";
700ba2cbe9Sxc 		break;
710ba2cbe9Sxc 	case DLADM_STATUS_EXIST:
720ba2cbe9Sxc 		s = "object already exists";
730ba2cbe9Sxc 		break;
740ba2cbe9Sxc 	case DLADM_STATUS_LINKINVAL:
750ba2cbe9Sxc 		s = "invalid link";
760ba2cbe9Sxc 		break;
770ba2cbe9Sxc 	case DLADM_STATUS_PROPRDONLY:
780ba2cbe9Sxc 		s = "read-only property";
790ba2cbe9Sxc 		break;
800ba2cbe9Sxc 	case DLADM_STATUS_BADVALCNT:
810ba2cbe9Sxc 		s = "invalid number of values";
820ba2cbe9Sxc 		break;
830ba2cbe9Sxc 	case DLADM_STATUS_DBNOTFOUND:
840ba2cbe9Sxc 		s = "database not found";
850ba2cbe9Sxc 		break;
860ba2cbe9Sxc 	case DLADM_STATUS_DENIED:
870ba2cbe9Sxc 		s = "permission denied";
880ba2cbe9Sxc 		break;
890ba2cbe9Sxc 	case DLADM_STATUS_IOERR:
900ba2cbe9Sxc 		s = "I/O error";
910ba2cbe9Sxc 		break;
92f4b3ec61Sdh 	case DLADM_STATUS_TEMPONLY:
93*da14cebeSEric Cheng 		s = "change cannot be persistent";
94f4b3ec61Sdh 		break;
95f595a68aSyz 	case DLADM_STATUS_TIMEDOUT:
96f595a68aSyz 		s = "operation timed out";
97f595a68aSyz 		break;
98f595a68aSyz 	case DLADM_STATUS_ISCONN:
99f595a68aSyz 		s = "already connected";
100f595a68aSyz 		break;
101f595a68aSyz 	case DLADM_STATUS_NOTCONN:
102f595a68aSyz 		s = "not connected";
103f595a68aSyz 		break;
104f595a68aSyz 	case DLADM_STATUS_REPOSITORYINVAL:
105f595a68aSyz 		s = "invalid configuration repository";
106f595a68aSyz 		break;
107f595a68aSyz 	case DLADM_STATUS_MACADDRINVAL:
108f595a68aSyz 		s = "invalid MAC address";
109f595a68aSyz 		break;
110f595a68aSyz 	case DLADM_STATUS_KEYINVAL:
111f595a68aSyz 		s = "invalid key";
112f595a68aSyz 		break;
113843e1988Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRLEN:
114843e1988Sjohnlev 		s = "invalid MAC address length";
115843e1988Sjohnlev 		break;
116843e1988Sjohnlev 	case DLADM_STATUS_INVALIDMACADDRTYPE:
117843e1988Sjohnlev 		s = "invalid MAC address type";
118843e1988Sjohnlev 		break;
119d62bc4baSyz 	case DLADM_STATUS_LINKBUSY:
120d62bc4baSyz 		s = "link busy";
121d62bc4baSyz 		break;
122d62bc4baSyz 	case DLADM_STATUS_VIDINVAL:
123d62bc4baSyz 		s = "invalid VLAN identifier";
124843e1988Sjohnlev 		break;
125d62bc4baSyz 	case DLADM_STATUS_TRYAGAIN:
126d62bc4baSyz 		s = "try again later";
127843e1988Sjohnlev 		break;
128d62bc4baSyz 	case DLADM_STATUS_NONOTIF:
129d62bc4baSyz 		s = "link notification is not supported";
130843e1988Sjohnlev 		break;
131*da14cebeSEric Cheng 	case DLADM_STATUS_BADTIMEVAL:
132*da14cebeSEric Cheng 		s = "invalid time range";
133*da14cebeSEric Cheng 		break;
134*da14cebeSEric Cheng 	case DLADM_STATUS_INVALIDMACADDR:
135*da14cebeSEric Cheng 		s = "invalid MAC address value";
136*da14cebeSEric Cheng 		break;
137*da14cebeSEric Cheng 	case DLADM_STATUS_INVALIDMACADDRNIC:
138*da14cebeSEric Cheng 		s = "MAC address reserved for use by underlying data-link";
139*da14cebeSEric Cheng 		break;
140*da14cebeSEric Cheng 	case DLADM_STATUS_INVALIDMACADDRINUSE:
141*da14cebeSEric Cheng 		s = "MAC address is already in use";
142*da14cebeSEric Cheng 		break;
143*da14cebeSEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTINVALID:
144*da14cebeSEric Cheng 		s = "invalid factory MAC address slot";
145*da14cebeSEric Cheng 		break;
146*da14cebeSEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTUSED:
147*da14cebeSEric Cheng 		s = "factory MAC address slot already used";
148*da14cebeSEric Cheng 		break;
149*da14cebeSEric Cheng 	case DLADM_STATUS_MACFACTORYSLOTALLUSED:
150*da14cebeSEric Cheng 		s = "all factory MAC address slots are in use";
151*da14cebeSEric Cheng 		break;
152*da14cebeSEric Cheng 	case DLADM_STATUS_MACFACTORYNOTSUP:
153*da14cebeSEric Cheng 		s = "factory MAC address slots not supported";
154*da14cebeSEric Cheng 		break;
155*da14cebeSEric Cheng 	case DLADM_STATUS_INVALIDMACPREFIX:
156*da14cebeSEric Cheng 		s = "Invalid MAC address prefix value";
157*da14cebeSEric Cheng 		break;
158*da14cebeSEric Cheng 	case DLADM_STATUS_INVALIDMACPREFIXLEN:
159*da14cebeSEric Cheng 		s = "Invalid MAC address prefix length";
160*da14cebeSEric Cheng 		break;
161*da14cebeSEric Cheng 	case DLADM_STATUS_CPUMAX:
162*da14cebeSEric Cheng 		s = "non-existent processor ID";
163*da14cebeSEric Cheng 		break;
164*da14cebeSEric Cheng 	case DLADM_STATUS_CPUERR:
165*da14cebeSEric Cheng 		s = "could not determine processor status";
166*da14cebeSEric Cheng 		break;
167*da14cebeSEric Cheng 	case DLADM_STATUS_CPUNOTONLINE:
168*da14cebeSEric Cheng 		s = "processor not online";
169*da14cebeSEric Cheng 		break;
170*da14cebeSEric Cheng 	case DLADM_STATUS_DB_NOTFOUND:
171*da14cebeSEric Cheng 		s = "database not found";
172*da14cebeSEric Cheng 		break;
173*da14cebeSEric Cheng 	case DLADM_STATUS_DB_PARSE_ERR:
174*da14cebeSEric Cheng 		s = "database parse error";
175*da14cebeSEric Cheng 		break;
176*da14cebeSEric Cheng 	case DLADM_STATUS_PROP_PARSE_ERR:
177*da14cebeSEric Cheng 		s = "property parse error";
178*da14cebeSEric Cheng 		break;
179*da14cebeSEric Cheng 	case DLADM_STATUS_ATTR_PARSE_ERR:
180*da14cebeSEric Cheng 		s = "attribute parse error";
181*da14cebeSEric Cheng 		break;
182*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_DB_ERR:
183*da14cebeSEric Cheng 		s = "flow database error";
184*da14cebeSEric Cheng 		break;
185*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_DB_OPEN_ERR:
186*da14cebeSEric Cheng 		s = "flow database open error";
187*da14cebeSEric Cheng 		break;
188*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_DB_PARSE_ERR:
189*da14cebeSEric Cheng 		s = "flow database parse error";
190*da14cebeSEric Cheng 		break;
191*da14cebeSEric Cheng 	case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR:
192*da14cebeSEric Cheng 		s = "flow property database parse error";
193*da14cebeSEric Cheng 		break;
194*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_ADD_ERR:
195*da14cebeSEric Cheng 		s = "flow add error";
196*da14cebeSEric Cheng 		break;
197*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_WALK_ERR:
198*da14cebeSEric Cheng 		s = "flow walk error";
199*da14cebeSEric Cheng 		break;
200*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_IDENTICAL:
201*da14cebeSEric Cheng 		s = "a flow with identical attributes exists";
202*da14cebeSEric Cheng 		break;
203*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_INCOMPATIBLE:
204*da14cebeSEric Cheng 		s = "flow(s) with incompatible attributes exists";
205*da14cebeSEric Cheng 		break;
206*da14cebeSEric Cheng 	case DLADM_STATUS_FLOW_EXISTS:
207*da14cebeSEric Cheng 		s = "link still has flows";
208*da14cebeSEric Cheng 		break;
209*da14cebeSEric Cheng 	case DLADM_STATUS_PERSIST_FLOW_EXISTS:
210*da14cebeSEric Cheng 		s = "persistent flow with the same name exists";
211*da14cebeSEric Cheng 		break;
212*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_IP:
213*da14cebeSEric Cheng 		s = "invalid IP address";
214*da14cebeSEric Cheng 		break;
215*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_PREFIXLEN:
216*da14cebeSEric Cheng 		s = "invalid IP prefix length";
217*da14cebeSEric Cheng 		break;
218*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_PROTOCOL:
219*da14cebeSEric Cheng 		s = "invalid IP protocol";
220*da14cebeSEric Cheng 		break;
221*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_PORT:
222*da14cebeSEric Cheng 		s = "invalid port number";
223*da14cebeSEric Cheng 		break;
224*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_DSF:
225*da14cebeSEric Cheng 		s = "invalid dsfield";
226*da14cebeSEric Cheng 		break;
227*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_DSFMASK:
228*da14cebeSEric Cheng 		s = "invalid dsfield mask";
229*da14cebeSEric Cheng 		break;
230*da14cebeSEric Cheng 	case DLADM_STATUS_INVALID_MACMARGIN:
231*da14cebeSEric Cheng 		s = "MTU check failed, use lower MTU or -f option";
232*da14cebeSEric Cheng 		break;
233*da14cebeSEric Cheng 	case DLADM_STATUS_BADPROP:
234*da14cebeSEric Cheng 		s = "invalid property";
235*da14cebeSEric Cheng 		break;
236*da14cebeSEric Cheng 	case DLADM_STATUS_MINMAXBW:
237*da14cebeSEric Cheng 		s = "minimum value for maxbw is 1.2M";
238*da14cebeSEric Cheng 		break;
239*da14cebeSEric Cheng 	case DLADM_STATUS_NO_HWRINGS:
240*da14cebeSEric Cheng 		s = "request hw rings failed";
241*da14cebeSEric Cheng 		break;
2420ba2cbe9Sxc 	default:
24333343a97Smeem 		s = "<unknown error>";
24433343a97Smeem 		break;
2450ba2cbe9Sxc 	}
24633343a97Smeem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
2470ba2cbe9Sxc 	return (buf);
2480ba2cbe9Sxc }
2490ba2cbe9Sxc 
2500ba2cbe9Sxc /*
2510ba2cbe9Sxc  * Convert a unix errno to a dladm_status_t.
2520ba2cbe9Sxc  * We only convert errnos that are likely to be encountered. All others
2530ba2cbe9Sxc  * are mapped to DLADM_STATUS_FAILED.
2540ba2cbe9Sxc  */
2550ba2cbe9Sxc dladm_status_t
2560ba2cbe9Sxc dladm_errno2status(int err)
2570ba2cbe9Sxc {
2580ba2cbe9Sxc 	switch (err) {
259e7801d59Ssowmini 	case 0:
260e7801d59Ssowmini 		return (DLADM_STATUS_OK);
2610ba2cbe9Sxc 	case EINVAL:
2620ba2cbe9Sxc 		return (DLADM_STATUS_BADARG);
2630ba2cbe9Sxc 	case EEXIST:
2640ba2cbe9Sxc 		return (DLADM_STATUS_EXIST);
2650ba2cbe9Sxc 	case ENOENT:
2660ba2cbe9Sxc 		return (DLADM_STATUS_NOTFOUND);
2670ba2cbe9Sxc 	case ENOSPC:
2680ba2cbe9Sxc 		return (DLADM_STATUS_TOOSMALL);
2690ba2cbe9Sxc 	case ENOMEM:
2700ba2cbe9Sxc 		return (DLADM_STATUS_NOMEM);
2710ba2cbe9Sxc 	case ENOTSUP:
2720ba2cbe9Sxc 		return (DLADM_STATUS_NOTSUP);
273d62bc4baSyz 	case ENETDOWN:
274d62bc4baSyz 		return (DLADM_STATUS_NONOTIF);
2750ba2cbe9Sxc 	case EACCES:
276eae72b5bSSebastien Roy 	case EPERM:
2770ba2cbe9Sxc 		return (DLADM_STATUS_DENIED);
2780ba2cbe9Sxc 	case EIO:
2790ba2cbe9Sxc 		return (DLADM_STATUS_IOERR);
280843e1988Sjohnlev 	case EBUSY:
281d62bc4baSyz 		return (DLADM_STATUS_LINKBUSY);
282d62bc4baSyz 	case EAGAIN:
283d62bc4baSyz 		return (DLADM_STATUS_TRYAGAIN);
284*da14cebeSEric Cheng 	case ENOTEMPTY:
285*da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_EXISTS);
286*da14cebeSEric Cheng 	case EOPNOTSUPP:
287*da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_INCOMPATIBLE);
288*da14cebeSEric Cheng 	case EALREADY:
289*da14cebeSEric Cheng 		return (DLADM_STATUS_FLOW_IDENTICAL);
2900ba2cbe9Sxc 	default:
2910ba2cbe9Sxc 		return (DLADM_STATUS_FAILED);
2920ba2cbe9Sxc 	}
2930ba2cbe9Sxc }
2940ba2cbe9Sxc 
295*da14cebeSEric Cheng dladm_status_t
296*da14cebeSEric Cheng dladm_str2bw(char *oarg, uint64_t *bw)
297*da14cebeSEric Cheng {
298*da14cebeSEric Cheng 	char		*endp = NULL;
299*da14cebeSEric Cheng 	int64_t		n;
300*da14cebeSEric Cheng 	int		mult = 1;
301*da14cebeSEric Cheng 
302*da14cebeSEric Cheng 	n = strtoull(oarg, &endp, 10);
303*da14cebeSEric Cheng 
304*da14cebeSEric Cheng 	if ((errno != 0) || (strlen(endp) > 1))
305*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
306*da14cebeSEric Cheng 
307*da14cebeSEric Cheng 	if (n < 0)
308*da14cebeSEric Cheng 		return (DLADM_STATUS_BADVAL);
309*da14cebeSEric Cheng 
310*da14cebeSEric Cheng 	switch (*endp) {
311*da14cebeSEric Cheng 	case 'k':
312*da14cebeSEric Cheng 	case 'K':
313*da14cebeSEric Cheng 		mult = 1000;
314*da14cebeSEric Cheng 		break;
315*da14cebeSEric Cheng 	case 'm':
316*da14cebeSEric Cheng 	case 'M':
317*da14cebeSEric Cheng 	case '\0':
318*da14cebeSEric Cheng 		mult = 1000000;
319*da14cebeSEric Cheng 		break;
320*da14cebeSEric Cheng 	case 'g':
321*da14cebeSEric Cheng 	case 'G':
322*da14cebeSEric Cheng 		mult = 1000000000;
323*da14cebeSEric Cheng 		break;
324*da14cebeSEric Cheng 	case '%':
325*da14cebeSEric Cheng 		/*
326*da14cebeSEric Cheng 		 * percentages not supported for now,
327*da14cebeSEric Cheng 		 * see RFE 6540675
328*da14cebeSEric Cheng 		 */
329*da14cebeSEric Cheng 		return (DLADM_STATUS_NOTSUP);
330*da14cebeSEric Cheng 	default:
331*da14cebeSEric Cheng 		return (DLADM_STATUS_BADVAL);
332*da14cebeSEric Cheng 	}
333*da14cebeSEric Cheng 
334*da14cebeSEric Cheng 	*bw = n * mult;
335*da14cebeSEric Cheng 
336*da14cebeSEric Cheng 	/* check for overflow */
337*da14cebeSEric Cheng 	if (*bw / mult != n)
338*da14cebeSEric Cheng 		return (DLADM_STATUS_BADARG);
339*da14cebeSEric Cheng 
340*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
341*da14cebeSEric Cheng }
342*da14cebeSEric Cheng 
343*da14cebeSEric Cheng /*
344*da14cebeSEric Cheng  * Convert bandwidth in bps to a string in mpbs.  For values greater
345*da14cebeSEric Cheng  * than 1mbps or 1000000, print a whole mbps value.  For values that
346*da14cebeSEric Cheng  * have fractional Mbps in whole Kbps , print the bandwidth in a manner
347*da14cebeSEric Cheng  * simlilar to a floating point format.
348*da14cebeSEric Cheng  *
349*da14cebeSEric Cheng  *        bps       string
350*da14cebeSEric Cheng  *          0            0
351*da14cebeSEric Cheng  *        100            0
352*da14cebeSEric Cheng  *       2000        0.002
353*da14cebeSEric Cheng  *     431000        0.431
354*da14cebeSEric Cheng  *    1000000            1
355*da14cebeSEric Cheng  *    1030000        1.030
356*da14cebeSEric Cheng  *  100000000          100
357*da14cebeSEric Cheng  */
358*da14cebeSEric Cheng const char *
359*da14cebeSEric Cheng dladm_bw2str(int64_t bw, char *buf)
360*da14cebeSEric Cheng {
361*da14cebeSEric Cheng 	int kbps, mbps;
362*da14cebeSEric Cheng 
363*da14cebeSEric Cheng 	kbps = (bw%1000000)/1000;
364*da14cebeSEric Cheng 	mbps = bw/1000000;
365*da14cebeSEric Cheng 	if (kbps != 0) {
366*da14cebeSEric Cheng 		if (mbps == 0)
367*da14cebeSEric Cheng 			(void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps);
368*da14cebeSEric Cheng 		else
369*da14cebeSEric Cheng 			(void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps,
370*da14cebeSEric Cheng 			    kbps);
371*da14cebeSEric Cheng 	} else {
372*da14cebeSEric Cheng 		(void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps);
373*da14cebeSEric Cheng 	}
374*da14cebeSEric Cheng 
375*da14cebeSEric Cheng 	return (buf);
376*da14cebeSEric Cheng }
377*da14cebeSEric Cheng 
378d62bc4baSyz #define	LOCK_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
3790ba2cbe9Sxc 
3800ba2cbe9Sxc static int
3810ba2cbe9Sxc i_dladm_lock_db(const char *lock_file, short type)
3820ba2cbe9Sxc {
3830ba2cbe9Sxc 	int	lock_fd;
384d62bc4baSyz 	struct	flock lock;
3850ba2cbe9Sxc 
3860ba2cbe9Sxc 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
3870ba2cbe9Sxc 	    LOCK_DB_PERMS)) < 0)
3880ba2cbe9Sxc 		return (-1);
3890ba2cbe9Sxc 
3900ba2cbe9Sxc 	lock.l_type = type;
3910ba2cbe9Sxc 	lock.l_whence = SEEK_SET;
3920ba2cbe9Sxc 	lock.l_start = 0;
3930ba2cbe9Sxc 	lock.l_len = 0;
3940ba2cbe9Sxc 
3950ba2cbe9Sxc 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
3960ba2cbe9Sxc 		int err = errno;
3970ba2cbe9Sxc 
3980ba2cbe9Sxc 		(void) close(lock_fd);
3990ba2cbe9Sxc 		(void) unlink(lock_file);
4000ba2cbe9Sxc 		errno = err;
4010ba2cbe9Sxc 		return (-1);
4020ba2cbe9Sxc 	}
4030ba2cbe9Sxc 	return (lock_fd);
4040ba2cbe9Sxc }
4050ba2cbe9Sxc 
4060ba2cbe9Sxc static void
4070ba2cbe9Sxc i_dladm_unlock_db(const char *lock_file, int fd)
4080ba2cbe9Sxc {
4090ba2cbe9Sxc 	struct flock lock;
4100ba2cbe9Sxc 
4110ba2cbe9Sxc 	if (fd < 0)
4120ba2cbe9Sxc 		return;
4130ba2cbe9Sxc 
4140ba2cbe9Sxc 	lock.l_type = F_UNLCK;
4150ba2cbe9Sxc 	lock.l_whence = SEEK_SET;
4160ba2cbe9Sxc 	lock.l_start = 0;
4170ba2cbe9Sxc 	lock.l_len = 0;
4180ba2cbe9Sxc 
4190ba2cbe9Sxc 	(void) fcntl(fd, F_SETLKW, &lock);
4200ba2cbe9Sxc 	(void) close(fd);
4210ba2cbe9Sxc 	(void) unlink(lock_file);
4220ba2cbe9Sxc }
4230ba2cbe9Sxc 
424d62bc4baSyz /*
425d62bc4baSyz  * Given a link class, returns its class string.
426d62bc4baSyz  */
427d62bc4baSyz const char *
428d62bc4baSyz dladm_class2str(datalink_class_t class, char *buf)
429d62bc4baSyz {
430d62bc4baSyz 	const char *s;
431d62bc4baSyz 
432d62bc4baSyz 	switch (class) {
433d62bc4baSyz 	case DATALINK_CLASS_PHYS:
434d62bc4baSyz 		s = "phys";
435d62bc4baSyz 		break;
436d62bc4baSyz 	case DATALINK_CLASS_VLAN:
437d62bc4baSyz 		s = "vlan";
438d62bc4baSyz 		break;
439d62bc4baSyz 	case DATALINK_CLASS_AGGR:
440d62bc4baSyz 		s = "aggr";
441d62bc4baSyz 		break;
442d62bc4baSyz 	case DATALINK_CLASS_VNIC:
443d62bc4baSyz 		s = "vnic";
444d62bc4baSyz 		break;
445*da14cebeSEric Cheng 	case DATALINK_CLASS_ETHERSTUB:
446*da14cebeSEric Cheng 		s = "etherstub";
447*da14cebeSEric Cheng 		break;
448d62bc4baSyz 	default:
449d62bc4baSyz 		s = "unknown";
450d62bc4baSyz 		break;
451d62bc4baSyz 	}
452d62bc4baSyz 
453d62bc4baSyz 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
454d62bc4baSyz 	return (buf);
455d62bc4baSyz }
456d62bc4baSyz 
457d62bc4baSyz /*
458d62bc4baSyz  * Given a physical link media type, returns its media type string.
459d62bc4baSyz  */
460d62bc4baSyz const char *
461d62bc4baSyz dladm_media2str(uint32_t media, char *buf)
462d62bc4baSyz {
463d62bc4baSyz 	const char *s;
464d62bc4baSyz 
465d62bc4baSyz 	switch (media) {
466d62bc4baSyz 	case DL_ETHER:
467d62bc4baSyz 		s = "Ethernet";
468d62bc4baSyz 		break;
469d62bc4baSyz 	case DL_WIFI:
470d62bc4baSyz 		s = "WiFi";
471d62bc4baSyz 		break;
472d62bc4baSyz 	case DL_IB:
473d62bc4baSyz 		s = "Infiniband";
474d62bc4baSyz 		break;
475d62bc4baSyz 	case DL_IPV4:
476d62bc4baSyz 		s = "IPv4Tunnel";
477d62bc4baSyz 		break;
478d62bc4baSyz 	case DL_IPV6:
479d62bc4baSyz 		s = "IPv6Tunnel";
480d62bc4baSyz 		break;
481d62bc4baSyz 	case DL_CSMACD:
482d62bc4baSyz 		s = "CSMA/CD";
483d62bc4baSyz 		break;
484d62bc4baSyz 	case DL_TPB:
485d62bc4baSyz 		s = "TokenBus";
486d62bc4baSyz 		break;
487d62bc4baSyz 	case DL_TPR:
488d62bc4baSyz 		s = "TokenRing";
489d62bc4baSyz 		break;
490d62bc4baSyz 	case DL_METRO:
491d62bc4baSyz 		s = "MetroNet";
492d62bc4baSyz 		break;
493d62bc4baSyz 	case DL_HDLC:
494d62bc4baSyz 		s = "HDLC";
495d62bc4baSyz 		break;
496d62bc4baSyz 	case DL_CHAR:
497d62bc4baSyz 		s = "SyncCharacter";
498d62bc4baSyz 		break;
499d62bc4baSyz 	case DL_CTCA:
500d62bc4baSyz 		s = "CTCA";
501d62bc4baSyz 		break;
502d62bc4baSyz 	case DL_FDDI:
503d62bc4baSyz 		s = "FDDI";
504d62bc4baSyz 		break;
505d62bc4baSyz 	case DL_FC:
506d62bc4baSyz 		s = "FiberChannel";
507d62bc4baSyz 		break;
508d62bc4baSyz 	case DL_ATM:
509d62bc4baSyz 		s = "ATM";
510d62bc4baSyz 		break;
511d62bc4baSyz 	case DL_IPATM:
512d62bc4baSyz 		s = "ATM(ClassicIP)";
513d62bc4baSyz 		break;
514d62bc4baSyz 	case DL_X25:
515d62bc4baSyz 		s = "X.25";
516d62bc4baSyz 		break;
517d62bc4baSyz 	case DL_IPX25:
518d62bc4baSyz 		s = "X.25(ClassicIP)";
519d62bc4baSyz 		break;
520d62bc4baSyz 	case DL_ISDN:
521d62bc4baSyz 		s = "ISDN";
522d62bc4baSyz 		break;
523d62bc4baSyz 	case DL_HIPPI:
524d62bc4baSyz 		s = "HIPPI";
525d62bc4baSyz 		break;
526d62bc4baSyz 	case DL_100VG:
527d62bc4baSyz 		s = "100BaseVGEthernet";
528d62bc4baSyz 		break;
529d62bc4baSyz 	case DL_100VGTPR:
530d62bc4baSyz 		s = "100BaseVGTokenRing";
531d62bc4baSyz 		break;
532d62bc4baSyz 	case DL_ETH_CSMA:
533d62bc4baSyz 		s = "IEEE802.3";
534d62bc4baSyz 		break;
535d62bc4baSyz 	case DL_100BT:
536d62bc4baSyz 		s = "100BaseT";
537d62bc4baSyz 		break;
538d62bc4baSyz 	case DL_FRAME:
539d62bc4baSyz 		s = "FrameRelay";
540d62bc4baSyz 		break;
541d62bc4baSyz 	case DL_MPFRAME:
542d62bc4baSyz 		s = "MPFrameRelay";
543d62bc4baSyz 		break;
544d62bc4baSyz 	case DL_ASYNC:
545d62bc4baSyz 		s = "AsyncCharacter";
546d62bc4baSyz 		break;
547b127ac41SPhilip Kirk 	case DL_IPNET:
548b127ac41SPhilip Kirk 		s = "IPNET";
549b127ac41SPhilip Kirk 		break;
550d62bc4baSyz 	default:
551d62bc4baSyz 		s = "--";
552d62bc4baSyz 		break;
553d62bc4baSyz 	}
554d62bc4baSyz 
555d62bc4baSyz 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
556d62bc4baSyz 	return (buf);
557d62bc4baSyz }
558d62bc4baSyz 
5590ba2cbe9Sxc dladm_status_t
5600ba2cbe9Sxc i_dladm_rw_db(const char *db_file, mode_t db_perms,
5610ba2cbe9Sxc     dladm_status_t (*process_db)(void *, FILE *, FILE *),
5620ba2cbe9Sxc     void *arg, boolean_t writeop)
5630ba2cbe9Sxc {
5640ba2cbe9Sxc 	dladm_status_t	status = DLADM_STATUS_OK;
5650ba2cbe9Sxc 	FILE		*fp, *nfp = NULL;
5660ba2cbe9Sxc 	char		lock[MAXPATHLEN];
5670ba2cbe9Sxc 	char		file[MAXPATHLEN];
5680ba2cbe9Sxc 	char		newfile[MAXPATHLEN];
5690ba2cbe9Sxc 	char		*db_basename;
5700ba2cbe9Sxc 	int		nfd, lock_fd;
5710ba2cbe9Sxc 
5720ba2cbe9Sxc 	/*
5730ba2cbe9Sxc 	 * If we are called from a boot script such as net-physical,
5740ba2cbe9Sxc 	 * it's quite likely that the root fs is still not writable.
5750ba2cbe9Sxc 	 * For this case, it's ok for the lock creation to fail since
5760ba2cbe9Sxc 	 * no one else could be accessing our configuration file.
5770ba2cbe9Sxc 	 */
5780ba2cbe9Sxc 	db_basename = strrchr(db_file, '/');
5790ba2cbe9Sxc 	if (db_basename == NULL || db_basename[1] == '\0')
5800ba2cbe9Sxc 		return (dladm_errno2status(EINVAL));
5810ba2cbe9Sxc 	db_basename++;
5820ba2cbe9Sxc 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
5830ba2cbe9Sxc 	if ((lock_fd = i_dladm_lock_db
5840ba2cbe9Sxc 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
5850ba2cbe9Sxc 		return (dladm_errno2status(errno));
5860ba2cbe9Sxc 
5870ba2cbe9Sxc 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
5880ba2cbe9Sxc 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
5890ba2cbe9Sxc 		int	err = errno;
5900ba2cbe9Sxc 
5910ba2cbe9Sxc 		i_dladm_unlock_db(lock, lock_fd);
5920ba2cbe9Sxc 		if (err == ENOENT)
5930ba2cbe9Sxc 			return (DLADM_STATUS_DBNOTFOUND);
5940ba2cbe9Sxc 
5950ba2cbe9Sxc 		return (dladm_errno2status(err));
5960ba2cbe9Sxc 	}
5970ba2cbe9Sxc 
5980ba2cbe9Sxc 	if (writeop) {
5990ba2cbe9Sxc 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
6000ba2cbe9Sxc 		    dladm_rootdir, db_file);
6010ba2cbe9Sxc 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
6020ba2cbe9Sxc 		    db_perms)) < 0) {
6030ba2cbe9Sxc 			(void) fclose(fp);
6040ba2cbe9Sxc 			i_dladm_unlock_db(lock, lock_fd);
6050ba2cbe9Sxc 			return (dladm_errno2status(errno));
6060ba2cbe9Sxc 		}
6070ba2cbe9Sxc 
6080ba2cbe9Sxc 		if ((nfp = fdopen(nfd, "w")) == NULL) {
6090ba2cbe9Sxc 			(void) close(nfd);
6100ba2cbe9Sxc 			(void) fclose(fp);
6110ba2cbe9Sxc 			(void) unlink(newfile);
6120ba2cbe9Sxc 			i_dladm_unlock_db(lock, lock_fd);
6130ba2cbe9Sxc 			return (dladm_errno2status(errno));
6140ba2cbe9Sxc 		}
6150ba2cbe9Sxc 	}
6160ba2cbe9Sxc 	status = (*process_db)(arg, fp, nfp);
6170ba2cbe9Sxc 	if (!writeop || status != DLADM_STATUS_OK)
6180ba2cbe9Sxc 		goto done;
6190ba2cbe9Sxc 
6200ba2cbe9Sxc 	/*
6210ba2cbe9Sxc 	 * Configuration files need to be owned by the 'dladm' user.
6220ba2cbe9Sxc 	 * If we are invoked by root, the file ownership needs to be fixed.
6230ba2cbe9Sxc 	 */
6240ba2cbe9Sxc 	if (getuid() == 0 || geteuid() == 0) {
625b9e076dcSyz 		if (fchown(nfd, UID_DLADM, GID_SYS) < 0) {
6260ba2cbe9Sxc 			status = dladm_errno2status(errno);
6270ba2cbe9Sxc 			goto done;
6280ba2cbe9Sxc 		}
6290ba2cbe9Sxc 	}
6300ba2cbe9Sxc 
6310ba2cbe9Sxc 	if (fflush(nfp) == EOF) {
6320ba2cbe9Sxc 		status = dladm_errno2status(errno);
6330ba2cbe9Sxc 		goto done;
6340ba2cbe9Sxc 	}
6350ba2cbe9Sxc 	(void) fclose(fp);
6360ba2cbe9Sxc 	(void) fclose(nfp);
6370ba2cbe9Sxc 
6380ba2cbe9Sxc 	if (rename(newfile, file) < 0) {
6390ba2cbe9Sxc 		(void) unlink(newfile);
6400ba2cbe9Sxc 		i_dladm_unlock_db(lock, lock_fd);
6410ba2cbe9Sxc 		return (dladm_errno2status(errno));
6420ba2cbe9Sxc 	}
6430ba2cbe9Sxc 
6440ba2cbe9Sxc 	i_dladm_unlock_db(lock, lock_fd);
6450ba2cbe9Sxc 	return (DLADM_STATUS_OK);
6460ba2cbe9Sxc 
6470ba2cbe9Sxc done:
6480ba2cbe9Sxc 	if (nfp != NULL) {
6490ba2cbe9Sxc 		(void) fclose(nfp);
6500ba2cbe9Sxc 		if (status != DLADM_STATUS_OK)
6510ba2cbe9Sxc 			(void) unlink(newfile);
6520ba2cbe9Sxc 	}
6530ba2cbe9Sxc 	(void) fclose(fp);
6540ba2cbe9Sxc 	i_dladm_unlock_db(lock, lock_fd);
6550ba2cbe9Sxc 	return (status);
6560ba2cbe9Sxc }
6570ba2cbe9Sxc 
6580ba2cbe9Sxc dladm_status_t
6590ba2cbe9Sxc dladm_set_rootdir(const char *rootdir)
6600ba2cbe9Sxc {
6610ba2cbe9Sxc 	DIR	*dp;
6620ba2cbe9Sxc 
6630ba2cbe9Sxc 	if (rootdir == NULL || *rootdir != '/' ||
6640ba2cbe9Sxc 	    (dp = opendir(rootdir)) == NULL)
6650ba2cbe9Sxc 		return (DLADM_STATUS_BADARG);
6660ba2cbe9Sxc 
6670ba2cbe9Sxc 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
6680ba2cbe9Sxc 	(void) closedir(dp);
6690ba2cbe9Sxc 	return (DLADM_STATUS_OK);
6700ba2cbe9Sxc }
671d62bc4baSyz 
672d62bc4baSyz boolean_t
673d62bc4baSyz dladm_valid_linkname(const char *link)
674d62bc4baSyz {
675d62bc4baSyz 	size_t		len = strlen(link);
676d62bc4baSyz 	const char	*cp;
677d62bc4baSyz 
678d62bc4baSyz 	if (len + 1 >= MAXLINKNAMELEN)
679d62bc4baSyz 		return (B_FALSE);
680d62bc4baSyz 
681d62bc4baSyz 	/*
682d62bc4baSyz 	 * The link name cannot start with a digit and must end with a digit.
683d62bc4baSyz 	 */
684d62bc4baSyz 	if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0))
685d62bc4baSyz 		return (B_FALSE);
686d62bc4baSyz 
687d62bc4baSyz 	/*
688d62bc4baSyz 	 * The legal characters in a link name are:
689d62bc4baSyz 	 * alphanumeric (a-z,  A-Z,  0-9), and the underscore ('_').
690d62bc4baSyz 	 */
691d62bc4baSyz 	for (cp = link; *cp != '\0'; cp++) {
692d62bc4baSyz 		if ((isalnum(*cp) == 0) && (*cp != '_'))
693d62bc4baSyz 			return (B_FALSE);
694d62bc4baSyz 	}
695d62bc4baSyz 
696d62bc4baSyz 	return (B_TRUE);
697d62bc4baSyz }
698*da14cebeSEric Cheng 
699*da14cebeSEric Cheng /*
700*da14cebeSEric Cheng  * Convert priority string to a value.
701*da14cebeSEric Cheng  */
702*da14cebeSEric Cheng dladm_status_t
703*da14cebeSEric Cheng dladm_str2pri(char *token, mac_priority_level_t *pri)
704*da14cebeSEric Cheng {
705*da14cebeSEric Cheng 	if (strlen(token) == strlen("low") &&
706*da14cebeSEric Cheng 	    strncasecmp(token, "low", strlen("low")) == 0) {
707*da14cebeSEric Cheng 		*pri = MPL_LOW;
708*da14cebeSEric Cheng 	} else if (strlen(token) == strlen("medium") &&
709*da14cebeSEric Cheng 	    strncasecmp(token, "medium", strlen("medium")) == 0) {
710*da14cebeSEric Cheng 		*pri = MPL_MEDIUM;
711*da14cebeSEric Cheng 	} else if (strlen(token) == strlen("high") &&
712*da14cebeSEric Cheng 	    strncasecmp(token, "high", strlen("high")) == 0) {
713*da14cebeSEric Cheng 		*pri = MPL_HIGH;
714*da14cebeSEric Cheng 	} else {
715*da14cebeSEric Cheng 		return (DLADM_STATUS_BADVAL);
716*da14cebeSEric Cheng 	}
717*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
718*da14cebeSEric Cheng }
719*da14cebeSEric Cheng 
720*da14cebeSEric Cheng /*
721*da14cebeSEric Cheng  * Convert priority value to a string.
722*da14cebeSEric Cheng  */
723*da14cebeSEric Cheng const char *
724*da14cebeSEric Cheng dladm_pri2str(mac_priority_level_t pri, char *buf)
725*da14cebeSEric Cheng {
726*da14cebeSEric Cheng 	const char	*s;
727*da14cebeSEric Cheng 
728*da14cebeSEric Cheng 	switch (pri) {
729*da14cebeSEric Cheng 	case MPL_LOW:
730*da14cebeSEric Cheng 		s = "low";
731*da14cebeSEric Cheng 		break;
732*da14cebeSEric Cheng 	case MPL_MEDIUM:
733*da14cebeSEric Cheng 		s = "medium";
734*da14cebeSEric Cheng 		break;
735*da14cebeSEric Cheng 	case MPL_HIGH:
736*da14cebeSEric Cheng 		s = "high";
737*da14cebeSEric Cheng 		break;
738*da14cebeSEric Cheng 	default:
739*da14cebeSEric Cheng 		s = "--";
740*da14cebeSEric Cheng 		break;
741*da14cebeSEric Cheng 	}
742*da14cebeSEric Cheng 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
743*da14cebeSEric Cheng 	return (buf);
744*da14cebeSEric Cheng }
745*da14cebeSEric Cheng 
746*da14cebeSEric Cheng void
747*da14cebeSEric Cheng dladm_free_args(dladm_arg_list_t *list)
748*da14cebeSEric Cheng {
749*da14cebeSEric Cheng 	if (list != NULL) {
750*da14cebeSEric Cheng 		free(list->al_buf);
751*da14cebeSEric Cheng 		free(list);
752*da14cebeSEric Cheng 	}
753*da14cebeSEric Cheng }
754*da14cebeSEric Cheng 
755*da14cebeSEric Cheng dladm_status_t
756*da14cebeSEric Cheng dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues)
757*da14cebeSEric Cheng {
758*da14cebeSEric Cheng 	dladm_arg_list_t	*list;
759*da14cebeSEric Cheng 	dladm_arg_info_t	*aip;
760*da14cebeSEric Cheng 	char			*buf, *curr;
761*da14cebeSEric Cheng 	int			len, i;
762*da14cebeSEric Cheng 
763*da14cebeSEric Cheng 	list = malloc(sizeof (dladm_arg_list_t));
764*da14cebeSEric Cheng 	if (list == NULL)
765*da14cebeSEric Cheng 		return (dladm_errno2status(errno));
766*da14cebeSEric Cheng 
767*da14cebeSEric Cheng 	list->al_count = 0;
768*da14cebeSEric Cheng 	list->al_buf = buf = strdup(str);
769*da14cebeSEric Cheng 	if (buf == NULL)
770*da14cebeSEric Cheng 		return (dladm_errno2status(errno));
771*da14cebeSEric Cheng 
772*da14cebeSEric Cheng 	curr = buf;
773*da14cebeSEric Cheng 	len = strlen(buf);
774*da14cebeSEric Cheng 	aip = NULL;
775*da14cebeSEric Cheng 	for (i = 0; i < len; i++) {
776*da14cebeSEric Cheng 		char		c = buf[i];
777*da14cebeSEric Cheng 		boolean_t	match = (c == '=' || c == ',');
778*da14cebeSEric Cheng 
779*da14cebeSEric Cheng 		if (!match && i != len - 1)
780*da14cebeSEric Cheng 			continue;
781*da14cebeSEric Cheng 
782*da14cebeSEric Cheng 		if (match) {
783*da14cebeSEric Cheng 			buf[i] = '\0';
784*da14cebeSEric Cheng 			if (*curr == '\0')
785*da14cebeSEric Cheng 				goto fail;
786*da14cebeSEric Cheng 		}
787*da14cebeSEric Cheng 
788*da14cebeSEric Cheng 		if (aip != NULL && c != '=') {
789*da14cebeSEric Cheng 			if (aip->ai_count > DLADM_MAX_ARG_VALS)
790*da14cebeSEric Cheng 				goto fail;
791*da14cebeSEric Cheng 
792*da14cebeSEric Cheng 			if (novalues)
793*da14cebeSEric Cheng 				goto fail;
794*da14cebeSEric Cheng 
795*da14cebeSEric Cheng 			aip->ai_val[aip->ai_count] = curr;
796*da14cebeSEric Cheng 			aip->ai_count++;
797*da14cebeSEric Cheng 		} else {
798*da14cebeSEric Cheng 			if (list->al_count > DLADM_MAX_ARG_VALS)
799*da14cebeSEric Cheng 				goto fail;
800*da14cebeSEric Cheng 
801*da14cebeSEric Cheng 			aip = &list->al_info[list->al_count];
802*da14cebeSEric Cheng 			aip->ai_name = curr;
803*da14cebeSEric Cheng 			aip->ai_count = 0;
804*da14cebeSEric Cheng 			list->al_count++;
805*da14cebeSEric Cheng 			if (c == ',')
806*da14cebeSEric Cheng 				aip = NULL;
807*da14cebeSEric Cheng 		}
808*da14cebeSEric Cheng 		curr = buf + i + 1;
809*da14cebeSEric Cheng 	}
810*da14cebeSEric Cheng 
811*da14cebeSEric Cheng 	*listp = list;
812*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
813*da14cebeSEric Cheng 
814*da14cebeSEric Cheng fail:
815*da14cebeSEric Cheng 	dladm_free_args(list);
816*da14cebeSEric Cheng 	return (DLADM_STATUS_FAILED);
817*da14cebeSEric Cheng }
818