Home | History | Annotate | Download | only in common
      1      0     stevel /*
      2      0     stevel  * CDDL HEADER START
      3      0     stevel  *
      4      0     stevel  * The contents of this file are subject to the terms of the
      5   2311        seb  * Common Development and Distribution License (the "License").
      6   2311        seb  * You may not use this file except in compliance with the License.
      7      0     stevel  *
      8      0     stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0     stevel  * or http://www.opensolaris.org/os/licensing.
     10      0     stevel  * See the License for the specific language governing permissions
     11      0     stevel  * and limitations under the License.
     12      0     stevel  *
     13      0     stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0     stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0     stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0     stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0     stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0     stevel  *
     19      0     stevel  * CDDL HEADER END
     20      0     stevel  */
     21      0     stevel /*
     22   9055    Michael  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0     stevel  * Use is subject to license terms.
     24      0     stevel  */
     25      0     stevel 
     26      0     stevel #include <unistd.h>
     27      0     stevel #include <errno.h>
     28   5895   yz147064 #include <ctype.h>
     29   3147   xc151355 #include <fcntl.h>
     30   3147   xc151355 #include <strings.h>
     31   3147   xc151355 #include <dirent.h>
     32   8275       Eric #include <stdlib.h>
     33  10734       Eric #include <netinet/in.h>
     34  10734       Eric #include <arpa/inet.h>
     35   6173   yz147064 #include <sys/param.h>
     36   3147   xc151355 #include <sys/stat.h>
     37   8453     Anurag #include <sys/dld.h>
     38   9107      james #include <sys/dld_ioc.h>
     39   3147   xc151355 #include <libdladm_impl.h>
     40   3184       meem #include <libintl.h>
     41   5895   yz147064 #include <libdlpi.h>
     42      0     stevel 
     43   8453     Anurag static char	dladm_rootdir[MAXPATHLEN] = "/";
     44   9815      Rishi 
     45   9815      Rishi typedef struct media_type_desc {
     46   9815      Rishi 	uint32_t	media_type;
     47   9815      Rishi #define	MAX_MEDIA_TYPE_STRING	32
     48   9815      Rishi 	const char	media_type_str[MAX_MEDIA_TYPE_STRING];
     49   9815      Rishi } media_type_t;
     50   9815      Rishi 
     51   9815      Rishi static media_type_t media_type_table[] =  {
     52   9815      Rishi 	{ DL_ETHER,	"Ethernet" },
     53   9815      Rishi 	{ DL_WIFI,	"WiFi" },
     54   9815      Rishi 	{ DL_IB,	"Infiniband" },
     55   9815      Rishi 	{ DL_IPV4,	"IPv4Tunnel" },
     56   9815      Rishi 	{ DL_IPV6,	"IPv6Tunnel" },
     57  10616  Sebastien 	{ DL_6TO4,	"6to4Tunnel" },
     58   9815      Rishi 	{ DL_CSMACD,	"CSMA/CD" },
     59   9815      Rishi 	{ DL_TPB,	"TokenBus" },
     60   9815      Rishi 	{ DL_TPR,	"TokenRing" },
     61   9815      Rishi 	{ DL_METRO,	"MetroNet" },
     62   9815      Rishi 	{ DL_HDLC,	"HDLC" },
     63   9815      Rishi 	{ DL_CHAR,	"SyncCharacter" },
     64   9815      Rishi 	{ DL_CTCA,	"CTCA" },
     65   9815      Rishi 	{ DL_FDDI, 	"FDDI" },
     66   9815      Rishi 	{ DL_FC, 	"FiberChannel" },
     67   9815      Rishi 	{ DL_ATM, 	"ATM" },
     68   9815      Rishi 	{ DL_IPATM, 	"ATM(ClassicIP)" },
     69   9815      Rishi 	{ DL_X25, 	"X.25" },
     70   9815      Rishi 	{ DL_IPX25, 	"X.25(ClassicIP)" },
     71   9815      Rishi 	{ DL_ISDN, 	"ISDN" },
     72   9815      Rishi 	{ DL_HIPPI, 	"HIPPI" },
     73   9815      Rishi 	{ DL_100VG, 	"100BaseVGEthernet" },
     74   9815      Rishi 	{ DL_100VGTPR, 	"100BaseVGTokenRing" },
     75   9815      Rishi 	{ DL_ETH_CSMA, 	"IEEE802.3" },
     76   9815      Rishi 	{ DL_100BT, 	"100BaseT" },
     77   9815      Rishi 	{ DL_FRAME, 	"FrameRelay" },
     78   9815      Rishi 	{ DL_MPFRAME, 	"MPFrameRelay" },
     79   9815      Rishi 	{ DL_ASYNC, 	"AsyncCharacter" },
     80   9815      Rishi 	{ DL_IPNET, 	"IPNET" },
     81   9815      Rishi 	{ DL_OTHER, 	"Other" }
     82   9815      Rishi };
     83   9815      Rishi #define	MEDIATYPECOUNT	(sizeof (media_type_table) / sizeof (media_type_t))
     84  10734       Eric 
     85  10734       Eric typedef struct {
     86  10734       Eric 	uint32_t	lp_type;
     87  10734       Eric 	char		*lp_name;
     88  10734       Eric } link_protect_t;
     89  10734       Eric 
     90  10734       Eric static link_protect_t link_protect_types[] = {
     91  10734       Eric 	{ MPT_MACNOSPOOF, "mac-nospoof" },
     92  10734       Eric 	{ MPT_IPNOSPOOF, "ip-nospoof" },
     93  10734       Eric 	{ MPT_RESTRICTED, "restricted" }
     94  10734       Eric };
     95  10734       Eric #define	LPTYPES	(sizeof (link_protect_types) / sizeof (link_protect_t))
     96   8453     Anurag 
     97   8453     Anurag dladm_status_t
     98   8453     Anurag dladm_open(dladm_handle_t *handle)
     99   8453     Anurag {
    100   8453     Anurag 	int dld_fd;
    101   8453     Anurag 
    102   8453     Anurag 	if (handle == NULL)
    103   8453     Anurag 		return (DLADM_STATUS_BADARG);
    104   8453     Anurag 
    105   8453     Anurag 	if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0)
    106   8453     Anurag 		return (dladm_errno2status(errno));
    107   8453     Anurag 
    108   8453     Anurag 	/*
    109   8453     Anurag 	 * Don't open DLMGMT_DOOR now.  dlmgmtd(1M) is not able to
    110   8453     Anurag 	 * open the door when the dladm handle is opened because the
    111   8453     Anurag 	 * door hasn't been created yet at that time.  Thus, we must
    112   8453     Anurag 	 * open it on-demand in dladm_door_fd().  Move the open()
    113   8453     Anurag 	 * to dladm_door_fd() for all cases.
    114   8453     Anurag 	 */
    115   8453     Anurag 
    116   8453     Anurag 	if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) {
    117   8453     Anurag 		(void) close(dld_fd);
    118   8453     Anurag 		return (DLADM_STATUS_NOMEM);
    119   8453     Anurag 	}
    120   8453     Anurag 
    121   8453     Anurag 	(*handle)->dld_fd = dld_fd;
    122   8453     Anurag 	(*handle)->door_fd = -1;
    123   8453     Anurag 
    124   8453     Anurag 	return (DLADM_STATUS_OK);
    125   8453     Anurag }
    126   8453     Anurag 
    127   8453     Anurag void
    128   8453     Anurag dladm_close(dladm_handle_t handle)
    129   8453     Anurag {
    130   8453     Anurag 	if (handle != NULL) {
    131   8453     Anurag 		(void) close(handle->dld_fd);
    132   8453     Anurag 		if (handle->door_fd != -1)
    133   8453     Anurag 			(void) close(handle->door_fd);
    134   8453     Anurag 		free(handle);
    135   8453     Anurag 	}
    136   8453     Anurag }
    137   8453     Anurag 
    138   8453     Anurag int
    139   8453     Anurag dladm_dld_fd(dladm_handle_t handle)
    140   8453     Anurag {
    141   8453     Anurag 	return (handle->dld_fd);
    142   8453     Anurag }
    143   8453     Anurag 
    144   8453     Anurag /*
    145   8453     Anurag  * If DLMGMT_DOOR hasn't been opened in the handle yet, open it.
    146   8453     Anurag  */
    147   8453     Anurag dladm_status_t
    148   8453     Anurag dladm_door_fd(dladm_handle_t handle, int *door_fd)
    149   8453     Anurag {
    150   8453     Anurag 	int fd;
    151   8453     Anurag 
    152   8453     Anurag 	if (handle->door_fd == -1) {
    153   8453     Anurag 		if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0)
    154   8453     Anurag 			return (dladm_errno2status(errno));
    155   8453     Anurag 		handle->door_fd = fd;
    156   8453     Anurag 	}
    157   8453     Anurag 	*door_fd = handle->door_fd;
    158   8453     Anurag 
    159   8453     Anurag 	return (DLADM_STATUS_OK);
    160   8453     Anurag }
    161   3147   xc151355 
    162   3147   xc151355 const char *
    163   3147   xc151355 dladm_status2str(dladm_status_t status, char *buf)
    164   3147   xc151355 {
    165   3147   xc151355 	const char	*s;
    166   3147   xc151355 
    167   3147   xc151355 	switch (status) {
    168   3147   xc151355 	case DLADM_STATUS_OK:
    169   3147   xc151355 		s = "ok";
    170   3147   xc151355 		break;
    171   3147   xc151355 	case DLADM_STATUS_BADARG:
    172   3147   xc151355 		s = "invalid argument";
    173   3147   xc151355 		break;
    174   3147   xc151355 	case DLADM_STATUS_FAILED:
    175   3147   xc151355 		s = "operation failed";
    176   3147   xc151355 		break;
    177   3147   xc151355 	case DLADM_STATUS_TOOSMALL:
    178   3147   xc151355 		s = "buffer size too small";
    179   3147   xc151355 		break;
    180   3147   xc151355 	case DLADM_STATUS_NOTSUP:
    181   3147   xc151355 		s = "operation not supported";
    182   3147   xc151355 		break;
    183   3147   xc151355 	case DLADM_STATUS_NOTFOUND:
    184   3147   xc151355 		s = "object not found";
    185   3147   xc151355 		break;
    186   3147   xc151355 	case DLADM_STATUS_BADVAL:
    187   3147   xc151355 		s = "invalid value";
    188   3147   xc151355 		break;
    189   3147   xc151355 	case DLADM_STATUS_NOMEM:
    190   3147   xc151355 		s = "insufficient memory";
    191   3147   xc151355 		break;
    192   3147   xc151355 	case DLADM_STATUS_EXIST:
    193   3147   xc151355 		s = "object already exists";
    194   3147   xc151355 		break;
    195   3147   xc151355 	case DLADM_STATUS_LINKINVAL:
    196   3147   xc151355 		s = "invalid link";
    197   3147   xc151355 		break;
    198   3147   xc151355 	case DLADM_STATUS_PROPRDONLY:
    199   3147   xc151355 		s = "read-only property";
    200   3147   xc151355 		break;
    201   3147   xc151355 	case DLADM_STATUS_BADVALCNT:
    202   3147   xc151355 		s = "invalid number of values";
    203   3147   xc151355 		break;
    204   3147   xc151355 	case DLADM_STATUS_DBNOTFOUND:
    205   3147   xc151355 		s = "database not found";
    206   3147   xc151355 		break;
    207   3147   xc151355 	case DLADM_STATUS_DENIED:
    208   3147   xc151355 		s = "permission denied";
    209   3147   xc151355 		break;
    210   3147   xc151355 	case DLADM_STATUS_IOERR:
    211   3147   xc151355 		s = "I/O error";
    212   3448   dh155122 		break;
    213   3448   dh155122 	case DLADM_STATUS_TEMPONLY:
    214   8275       Eric 		s = "change cannot be persistent";
    215   3871   yz147064 		break;
    216   3871   yz147064 	case DLADM_STATUS_TIMEDOUT:
    217   3871   yz147064 		s = "operation timed out";
    218   3871   yz147064 		break;
    219   3871   yz147064 	case DLADM_STATUS_ISCONN:
    220   3871   yz147064 		s = "already connected";
    221   3871   yz147064 		break;
    222   3871   yz147064 	case DLADM_STATUS_NOTCONN:
    223   3871   yz147064 		s = "not connected";
    224   3871   yz147064 		break;
    225   3871   yz147064 	case DLADM_STATUS_REPOSITORYINVAL:
    226   3871   yz147064 		s = "invalid configuration repository";
    227   3871   yz147064 		break;
    228   3871   yz147064 	case DLADM_STATUS_MACADDRINVAL:
    229   3871   yz147064 		s = "invalid MAC address";
    230   3871   yz147064 		break;
    231   3871   yz147064 	case DLADM_STATUS_KEYINVAL:
    232   3871   yz147064 		s = "invalid key";
    233   3147   xc151355 		break;
    234   5084    johnlev 	case DLADM_STATUS_INVALIDMACADDRLEN:
    235   5084    johnlev 		s = "invalid MAC address length";
    236   5084    johnlev 		break;
    237   5084    johnlev 	case DLADM_STATUS_INVALIDMACADDRTYPE:
    238   5084    johnlev 		s = "invalid MAC address type";
    239   5084    johnlev 		break;
    240   5895   yz147064 	case DLADM_STATUS_LINKBUSY:
    241   5895   yz147064 		s = "link busy";
    242   5084    johnlev 		break;
    243   5895   yz147064 	case DLADM_STATUS_VIDINVAL:
    244   5895   yz147064 		s = "invalid VLAN identifier";
    245   5084    johnlev 		break;
    246   5895   yz147064 	case DLADM_STATUS_TRYAGAIN:
    247   5895   yz147064 		s = "try again later";
    248   5895   yz147064 		break;
    249   5895   yz147064 	case DLADM_STATUS_NONOTIF:
    250   5895   yz147064 		s = "link notification is not supported";
    251   8275       Eric 		break;
    252   8275       Eric 	case DLADM_STATUS_BADTIMEVAL:
    253   8275       Eric 		s = "invalid time range";
    254   8275       Eric 		break;
    255   8275       Eric 	case DLADM_STATUS_INVALIDMACADDR:
    256   8275       Eric 		s = "invalid MAC address value";
    257   8275       Eric 		break;
    258   8275       Eric 	case DLADM_STATUS_INVALIDMACADDRNIC:
    259   8275       Eric 		s = "MAC address reserved for use by underlying data-link";
    260   8275       Eric 		break;
    261   8275       Eric 	case DLADM_STATUS_INVALIDMACADDRINUSE:
    262   8275       Eric 		s = "MAC address is already in use";
    263   8275       Eric 		break;
    264   8275       Eric 	case DLADM_STATUS_MACFACTORYSLOTINVALID:
    265   8275       Eric 		s = "invalid factory MAC address slot";
    266   8275       Eric 		break;
    267   8275       Eric 	case DLADM_STATUS_MACFACTORYSLOTUSED:
    268   8275       Eric 		s = "factory MAC address slot already used";
    269   8275       Eric 		break;
    270   8275       Eric 	case DLADM_STATUS_MACFACTORYSLOTALLUSED:
    271   8275       Eric 		s = "all factory MAC address slots are in use";
    272   8275       Eric 		break;
    273   8275       Eric 	case DLADM_STATUS_MACFACTORYNOTSUP:
    274   8275       Eric 		s = "factory MAC address slots not supported";
    275   8275       Eric 		break;
    276   8275       Eric 	case DLADM_STATUS_INVALIDMACPREFIX:
    277   8275       Eric 		s = "Invalid MAC address prefix value";
    278   8275       Eric 		break;
    279   8275       Eric 	case DLADM_STATUS_INVALIDMACPREFIXLEN:
    280   8275       Eric 		s = "Invalid MAC address prefix length";
    281   8275       Eric 		break;
    282   8275       Eric 	case DLADM_STATUS_CPUMAX:
    283   8275       Eric 		s = "non-existent processor ID";
    284   8275       Eric 		break;
    285   8275       Eric 	case DLADM_STATUS_CPUERR:
    286   8275       Eric 		s = "could not determine processor status";
    287   8275       Eric 		break;
    288   8275       Eric 	case DLADM_STATUS_CPUNOTONLINE:
    289   8275       Eric 		s = "processor not online";
    290   8275       Eric 		break;
    291   8275       Eric 	case DLADM_STATUS_DB_NOTFOUND:
    292   8275       Eric 		s = "database not found";
    293   8275       Eric 		break;
    294   8275       Eric 	case DLADM_STATUS_DB_PARSE_ERR:
    295   8275       Eric 		s = "database parse error";
    296   8275       Eric 		break;
    297   8275       Eric 	case DLADM_STATUS_PROP_PARSE_ERR:
    298   8275       Eric 		s = "property parse error";
    299   8275       Eric 		break;
    300   8275       Eric 	case DLADM_STATUS_ATTR_PARSE_ERR:
    301   8275       Eric 		s = "attribute parse error";
    302   8275       Eric 		break;
    303   8275       Eric 	case DLADM_STATUS_FLOW_DB_ERR:
    304   8275       Eric 		s = "flow database error";
    305   8275       Eric 		break;
    306   8275       Eric 	case DLADM_STATUS_FLOW_DB_OPEN_ERR:
    307   8275       Eric 		s = "flow database open error";
    308   8275       Eric 		break;
    309   8275       Eric 	case DLADM_STATUS_FLOW_DB_PARSE_ERR:
    310   8275       Eric 		s = "flow database parse error";
    311   8275       Eric 		break;
    312   8275       Eric 	case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR:
    313   8275       Eric 		s = "flow property database parse error";
    314   8275       Eric 		break;
    315   8275       Eric 	case DLADM_STATUS_FLOW_ADD_ERR:
    316   8275       Eric 		s = "flow add error";
    317   8275       Eric 		break;
    318   8275       Eric 	case DLADM_STATUS_FLOW_WALK_ERR:
    319   8275       Eric 		s = "flow walk error";
    320   8275       Eric 		break;
    321   8275       Eric 	case DLADM_STATUS_FLOW_IDENTICAL:
    322   8275       Eric 		s = "a flow with identical attributes exists";
    323   8275       Eric 		break;
    324   8275       Eric 	case DLADM_STATUS_FLOW_INCOMPATIBLE:
    325   8275       Eric 		s = "flow(s) with incompatible attributes exists";
    326   8275       Eric 		break;
    327   8275       Eric 	case DLADM_STATUS_FLOW_EXISTS:
    328   8275       Eric 		s = "link still has flows";
    329   8275       Eric 		break;
    330   8275       Eric 	case DLADM_STATUS_PERSIST_FLOW_EXISTS:
    331   8275       Eric 		s = "persistent flow with the same name exists";
    332   8275       Eric 		break;
    333   8275       Eric 	case DLADM_STATUS_INVALID_IP:
    334   8275       Eric 		s = "invalid IP address";
    335   8275       Eric 		break;
    336   8275       Eric 	case DLADM_STATUS_INVALID_PREFIXLEN:
    337   8275       Eric 		s = "invalid IP prefix length";
    338   8275       Eric 		break;
    339   8275       Eric 	case DLADM_STATUS_INVALID_PROTOCOL:
    340   8275       Eric 		s = "invalid IP protocol";
    341   8275       Eric 		break;
    342   8275       Eric 	case DLADM_STATUS_INVALID_PORT:
    343   8275       Eric 		s = "invalid port number";
    344   8275       Eric 		break;
    345   8275       Eric 	case DLADM_STATUS_INVALID_DSF:
    346   8275       Eric 		s = "invalid dsfield";
    347   8275       Eric 		break;
    348   8275       Eric 	case DLADM_STATUS_INVALID_DSFMASK:
    349   8275       Eric 		s = "invalid dsfield mask";
    350   8275       Eric 		break;
    351   8275       Eric 	case DLADM_STATUS_INVALID_MACMARGIN:
    352   8275       Eric 		s = "MTU check failed, use lower MTU or -f option";
    353   8275       Eric 		break;
    354   8275       Eric 	case DLADM_STATUS_BADPROP:
    355   8275       Eric 		s = "invalid property";
    356   8275       Eric 		break;
    357   8275       Eric 	case DLADM_STATUS_MINMAXBW:
    358   8275       Eric 		s = "minimum value for maxbw is 1.2M";
    359   8275       Eric 		break;
    360   8275       Eric 	case DLADM_STATUS_NO_HWRINGS:
    361   8275       Eric 		s = "request hw rings failed";
    362   5084    johnlev 		break;
    363  10491      Rishi 	case DLADM_STATUS_PERMONLY:
    364  10491      Rishi 		s = "change must be persistent";
    365  10491      Rishi 		break;
    366  10491      Rishi 	case DLADM_STATUS_OPTMISSING:
    367  10491      Rishi 		s = "optional software not installed";
    368  10491      Rishi 		break;
    369  10616  Sebastien 	case DLADM_STATUS_IPTUNTYPE:
    370  10616  Sebastien 		s = "invalid IP tunnel type";
    371  10616  Sebastien 		break;
    372  10616  Sebastien 	case DLADM_STATUS_IPTUNTYPEREQD:
    373  10616  Sebastien 		s = "IP tunnel type required";
    374  10616  Sebastien 		break;
    375  10616  Sebastien 	case DLADM_STATUS_BADIPTUNLADDR:
    376  10616  Sebastien 		s = "invalid local IP tunnel address";
    377  10616  Sebastien 		break;
    378  10616  Sebastien 	case DLADM_STATUS_BADIPTUNRADDR:
    379  10616  Sebastien 		s = "invalid remote IP tunnel address";
    380  10616  Sebastien 		break;
    381  10616  Sebastien 	case DLADM_STATUS_ADDRINUSE:
    382  10616  Sebastien 		s = "address already in use";
    383  10616  Sebastien 		break;
    384   3147   xc151355 	default:
    385   3184       meem 		s = "<unknown error>";
    386   3184       meem 		break;
    387   3147   xc151355 	}
    388   3184       meem 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
    389   3147   xc151355 	return (buf);
    390   3147   xc151355 }
    391   3147   xc151355 
    392   3147   xc151355 /*
    393   3147   xc151355  * Convert a unix errno to a dladm_status_t.
    394   3147   xc151355  * We only convert errnos that are likely to be encountered. All others
    395   3147   xc151355  * are mapped to DLADM_STATUS_FAILED.
    396   3147   xc151355  */
    397   3147   xc151355 dladm_status_t
    398   3147   xc151355 dladm_errno2status(int err)
    399   3147   xc151355 {
    400   3147   xc151355 	switch (err) {
    401   5903    sowmini 	case 0:
    402   5903    sowmini 		return (DLADM_STATUS_OK);
    403   3147   xc151355 	case EINVAL:
    404   3147   xc151355 		return (DLADM_STATUS_BADARG);
    405   3147   xc151355 	case EEXIST:
    406   3147   xc151355 		return (DLADM_STATUS_EXIST);
    407   3147   xc151355 	case ENOENT:
    408   3147   xc151355 		return (DLADM_STATUS_NOTFOUND);
    409   3147   xc151355 	case ENOSPC:
    410   3147   xc151355 		return (DLADM_STATUS_TOOSMALL);
    411   3147   xc151355 	case ENOMEM:
    412   3147   xc151355 		return (DLADM_STATUS_NOMEM);
    413   3147   xc151355 	case ENOTSUP:
    414   3147   xc151355 		return (DLADM_STATUS_NOTSUP);
    415   5895   yz147064 	case ENETDOWN:
    416   5895   yz147064 		return (DLADM_STATUS_NONOTIF);
    417   3147   xc151355 	case EACCES:
    418   7408  Sebastien 	case EPERM:
    419   3147   xc151355 		return (DLADM_STATUS_DENIED);
    420   3147   xc151355 	case EIO:
    421   3147   xc151355 		return (DLADM_STATUS_IOERR);
    422   5084    johnlev 	case EBUSY:
    423   5895   yz147064 		return (DLADM_STATUS_LINKBUSY);
    424   5895   yz147064 	case EAGAIN:
    425   5895   yz147064 		return (DLADM_STATUS_TRYAGAIN);
    426   8275       Eric 	case ENOTEMPTY:
    427   8275       Eric 		return (DLADM_STATUS_FLOW_EXISTS);
    428   8275       Eric 	case EOPNOTSUPP:
    429   8275       Eric 		return (DLADM_STATUS_FLOW_INCOMPATIBLE);
    430   8275       Eric 	case EALREADY:
    431   8275       Eric 		return (DLADM_STATUS_FLOW_IDENTICAL);
    432  10616  Sebastien 	case EADDRINUSE:
    433  10616  Sebastien 		return (DLADM_STATUS_ADDRINUSE);
    434   3147   xc151355 	default:
    435   3147   xc151355 		return (DLADM_STATUS_FAILED);
    436   3147   xc151355 	}
    437   9055    Michael }
    438   9055    Michael 
    439   9055    Michael boolean_t
    440   9055    Michael dladm_str2interval(char *oarg, uint32_t *interval)
    441   9055    Michael {
    442   9055    Michael 	int		val;
    443   9055    Michael 	char		*endp = NULL;
    444   9055    Michael 
    445   9055    Michael 	errno = 0;
    446   9055    Michael 	val = strtol(oarg, &endp, 10);
    447   9055    Michael 	if (errno != 0 || val <= 0 || *endp != '\0')
    448   9055    Michael 		return (B_FALSE);
    449   9055    Michael 
    450   9055    Michael 	*interval = val;
    451   9055    Michael 
    452   9055    Michael 	return (B_TRUE);
    453   8275       Eric }
    454   8275       Eric 
    455   8275       Eric dladm_status_t
    456   8275       Eric dladm_str2bw(char *oarg, uint64_t *bw)
    457   8275       Eric {
    458   8275       Eric 	char		*endp = NULL;
    459   8275       Eric 	int64_t		n;
    460   8275       Eric 	int		mult = 1;
    461   8275       Eric 
    462   8275       Eric 	n = strtoull(oarg, &endp, 10);
    463   8275       Eric 
    464   8275       Eric 	if ((errno != 0) || (strlen(endp) > 1))
    465   8275       Eric 		return (DLADM_STATUS_BADARG);
    466   8275       Eric 
    467   8275       Eric 	if (n < 0)
    468   8275       Eric 		return (DLADM_STATUS_BADVAL);
    469   8275       Eric 
    470   8275       Eric 	switch (*endp) {
    471   8275       Eric 	case 'k':
    472   8275       Eric 	case 'K':
    473   8275       Eric 		mult = 1000;
    474   8275       Eric 		break;
    475   8275       Eric 	case 'm':
    476   8275       Eric 	case 'M':
    477   8275       Eric 	case '\0':
    478   8275       Eric 		mult = 1000000;
    479   8275       Eric 		break;
    480   8275       Eric 	case 'g':
    481   8275       Eric 	case 'G':
    482   8275       Eric 		mult = 1000000000;
    483   8275       Eric 		break;
    484   8275       Eric 	case '%':
    485   8275       Eric 		/*
    486   8275       Eric 		 * percentages not supported for now,
    487   8275       Eric 		 * see RFE 6540675
    488   8275       Eric 		 */
    489   8275       Eric 		return (DLADM_STATUS_NOTSUP);
    490   8275       Eric 	default:
    491   8275       Eric 		return (DLADM_STATUS_BADVAL);
    492   8275       Eric 	}
    493   8275       Eric 
    494   8275       Eric 	*bw = n * mult;
    495   8275       Eric 
    496   8275       Eric 	/* check for overflow */
    497   8275       Eric 	if (*bw / mult != n)
    498   8275       Eric 		return (DLADM_STATUS_BADARG);
    499   8275       Eric 
    500   8275       Eric 	return (DLADM_STATUS_OK);
    501   8275       Eric }
    502   8275       Eric 
    503   8275       Eric /*
    504   8275       Eric  * Convert bandwidth in bps to a string in mpbs.  For values greater
    505   8275       Eric  * than 1mbps or 1000000, print a whole mbps value.  For values that
    506   8275       Eric  * have fractional Mbps in whole Kbps , print the bandwidth in a manner
    507   8275       Eric  * simlilar to a floating point format.
    508   8275       Eric  *
    509   8275       Eric  *        bps       string
    510   8275       Eric  *          0            0
    511   8275       Eric  *        100            0
    512   8275       Eric  *       2000        0.002
    513   8275       Eric  *     431000        0.431
    514   8275       Eric  *    1000000            1
    515   8275       Eric  *    1030000        1.030
    516   8275       Eric  *  100000000          100
    517   8275       Eric  */
    518   8275       Eric const char *
    519   8275       Eric dladm_bw2str(int64_t bw, char *buf)
    520   8275       Eric {
    521   8275       Eric 	int kbps, mbps;
    522   8275       Eric 
    523   8275       Eric 	kbps = (bw%1000000)/1000;
    524   8275       Eric 	mbps = bw/1000000;
    525   8275       Eric 	if (kbps != 0) {
    526   8275       Eric 		if (mbps == 0)
    527   8275       Eric 			(void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps);
    528   8275       Eric 		else
    529   8275       Eric 			(void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps,
    530   8275       Eric 			    kbps);
    531   8275       Eric 	} else {
    532   8275       Eric 		(void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps);
    533   8275       Eric 	}
    534   8275       Eric 
    535   8275       Eric 	return (buf);
    536   3147   xc151355 }
    537   3147   xc151355 
    538   5895   yz147064 #define	LOCK_DB_PERMS	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
    539   3147   xc151355 
    540   3147   xc151355 static int
    541   3147   xc151355 i_dladm_lock_db(const char *lock_file, short type)
    542   3147   xc151355 {
    543   3147   xc151355 	int	lock_fd;
    544   5895   yz147064 	struct	flock lock;
    545   3147   xc151355 
    546   3147   xc151355 	if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC,
    547   3147   xc151355 	    LOCK_DB_PERMS)) < 0)
    548   3147   xc151355 		return (-1);
    549   3147   xc151355 
    550   3147   xc151355 	lock.l_type = type;
    551   3147   xc151355 	lock.l_whence = SEEK_SET;
    552   3147   xc151355 	lock.l_start = 0;
    553   3147   xc151355 	lock.l_len = 0;
    554   3147   xc151355 
    555   3147   xc151355 	if (fcntl(lock_fd, F_SETLKW, &lock) < 0) {
    556   3147   xc151355 		int err = errno;
    557   3147   xc151355 
    558   3147   xc151355 		(void) close(lock_fd);
    559   3147   xc151355 		(void) unlink(lock_file);
    560   3147   xc151355 		errno = err;
    561   3147   xc151355 		return (-1);
    562   3147   xc151355 	}
    563   3147   xc151355 	return (lock_fd);
    564   3147   xc151355 }
    565   3147   xc151355 
    566   3147   xc151355 static void
    567   3147   xc151355 i_dladm_unlock_db(const char *lock_file, int fd)
    568   3147   xc151355 {
    569   3147   xc151355 	struct flock lock;
    570   3147   xc151355 
    571   3147   xc151355 	if (fd < 0)
    572   3147   xc151355 		return;
    573   3147   xc151355 
    574   3147   xc151355 	lock.l_type = F_UNLCK;
    575   3147   xc151355 	lock.l_whence = SEEK_SET;
    576   3147   xc151355 	lock.l_start = 0;
    577   3147   xc151355 	lock.l_len = 0;
    578   3147   xc151355 
    579   3147   xc151355 	(void) fcntl(fd, F_SETLKW, &lock);
    580   3147   xc151355 	(void) close(fd);
    581   3147   xc151355 	(void) unlink(lock_file);
    582   5895   yz147064 }
    583   5895   yz147064 
    584   5895   yz147064 /*
    585   5895   yz147064  * Given a link class, returns its class string.
    586   5895   yz147064  */
    587   5895   yz147064 const char *
    588   5895   yz147064 dladm_class2str(datalink_class_t class, char *buf)
    589   5895   yz147064 {
    590   5895   yz147064 	const char *s;
    591   5895   yz147064 
    592   5895   yz147064 	switch (class) {
    593   5895   yz147064 	case DATALINK_CLASS_PHYS:
    594   5895   yz147064 		s = "phys";
    595   5895   yz147064 		break;
    596   5895   yz147064 	case DATALINK_CLASS_VLAN:
    597   5895   yz147064 		s = "vlan";
    598   5895   yz147064 		break;
    599   5895   yz147064 	case DATALINK_CLASS_AGGR:
    600   5895   yz147064 		s = "aggr";
    601   5895   yz147064 		break;
    602   5895   yz147064 	case DATALINK_CLASS_VNIC:
    603   5895   yz147064 		s = "vnic";
    604   8275       Eric 		break;
    605   8275       Eric 	case DATALINK_CLASS_ETHERSTUB:
    606   8275       Eric 		s = "etherstub";
    607  10616  Sebastien 		break;
    608  10616  Sebastien 	case DATALINK_CLASS_IPTUN:
    609  10616  Sebastien 		s = "iptun";
    610   5895   yz147064 		break;
    611   9815      Rishi 	case DATALINK_CLASS_SIMNET:
    612   9815      Rishi 		s = "simnet";
    613  10491      Rishi 		break;
    614  10491      Rishi 	case DATALINK_CLASS_BRIDGE:
    615  10491      Rishi 		s = "bridge";
    616   9815      Rishi 		break;
    617   5895   yz147064 	default:
    618   5895   yz147064 		s = "unknown";
    619   5895   yz147064 		break;
    620   5895   yz147064 	}
    621   5895   yz147064 
    622   5895   yz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
    623   5895   yz147064 	return (buf);
    624   5895   yz147064 }
    625   5895   yz147064 
    626   5895   yz147064 /*
    627   5895   yz147064  * Given a physical link media type, returns its media type string.
    628   5895   yz147064  */
    629   5895   yz147064 const char *
    630   5895   yz147064 dladm_media2str(uint32_t media, char *buf)
    631   5895   yz147064 {
    632   9815      Rishi 	const char *s = "--";
    633   9815      Rishi 	media_type_t *mt;
    634   9815      Rishi 	int idx;
    635   5895   yz147064 
    636   9815      Rishi 	for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
    637   9815      Rishi 		mt = media_type_table + idx;
    638   9815      Rishi 		if (mt->media_type == media) {
    639   9815      Rishi 			s = mt->media_type_str;
    640   9815      Rishi 			break;
    641   9815      Rishi 		}
    642   5895   yz147064 	}
    643   5895   yz147064 
    644   5895   yz147064 	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
    645   5895   yz147064 	return (buf);
    646   9815      Rishi }
    647   9815      Rishi 
    648   9815      Rishi /*
    649   9815      Rishi  * Given a physical link media type string, returns its media type constant.
    650   9815      Rishi  */
    651   9815      Rishi uint32_t
    652   9815      Rishi dladm_str2media(const char *buf)
    653   9815      Rishi {
    654   9815      Rishi 	media_type_t *mt;
    655   9815      Rishi 	int idx;
    656   9815      Rishi 
    657   9815      Rishi 	for (idx = 0; idx < MEDIATYPECOUNT; idx++) {
    658   9815      Rishi 		mt = media_type_table + idx;
    659   9815      Rishi 		if (strcasecmp(buf, mt->media_type_str) == 0)
    660   9815      Rishi 			return (mt->media_type);
    661   9815      Rishi 	}
    662   9815      Rishi 
    663   9815      Rishi 	return (DL_OTHER);
    664   3147   xc151355 }
    665   3147   xc151355 
    666   3147   xc151355 dladm_status_t
    667   8453     Anurag i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms,
    668   8453     Anurag     dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *),
    669   3147   xc151355     void *arg, boolean_t writeop)
    670   3147   xc151355 {
    671   3147   xc151355 	dladm_status_t	status = DLADM_STATUS_OK;
    672   3147   xc151355 	FILE		*fp, *nfp = NULL;
    673   3147   xc151355 	char		lock[MAXPATHLEN];
    674   3147   xc151355 	char		file[MAXPATHLEN];
    675   3147   xc151355 	char		newfile[MAXPATHLEN];
    676   3147   xc151355 	char		*db_basename;
    677   3147   xc151355 	int		nfd, lock_fd;
    678   3147   xc151355 
    679   3147   xc151355 	/*
    680   3147   xc151355 	 * If we are called from a boot script such as net-physical,
    681   3147   xc151355 	 * it's quite likely that the root fs is still not writable.
    682   3147   xc151355 	 * For this case, it's ok for the lock creation to fail since
    683   3147   xc151355 	 * no one else could be accessing our configuration file.
    684   3147   xc151355 	 */
    685   3147   xc151355 	db_basename = strrchr(db_file, '/');
    686   3147   xc151355 	if (db_basename == NULL || db_basename[1] == '\0')
    687   3147   xc151355 		return (dladm_errno2status(EINVAL));
    688   3147   xc151355 	db_basename++;
    689   3147   xc151355 	(void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename);
    690   3147   xc151355 	if ((lock_fd = i_dladm_lock_db
    691   3147   xc151355 	    (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS)
    692   3147   xc151355 		return (dladm_errno2status(errno));
    693   3147   xc151355 
    694   3147   xc151355 	(void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file);
    695   3147   xc151355 	if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
    696   3147   xc151355 		int	err = errno;
    697   3147   xc151355 
    698   3147   xc151355 		i_dladm_unlock_db(lock, lock_fd);
    699   3147   xc151355 		if (err == ENOENT)
    700   3147   xc151355 			return (DLADM_STATUS_DBNOTFOUND);
    701   3147   xc151355 
    702   3147   xc151355 		return (dladm_errno2status(err));
    703   3147   xc151355 	}
    704   3147   xc151355 
    705   3147   xc151355 	if (writeop) {
    706   3147   xc151355 		(void) snprintf(newfile, MAXPATHLEN, "%s/%s.new",
    707   3147   xc151355 		    dladm_rootdir, db_file);
    708   3147   xc151355 		if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
    709   3147   xc151355 		    db_perms)) < 0) {
    710   3147   xc151355 			(void) fclose(fp);
    711   3147   xc151355 			i_dladm_unlock_db(lock, lock_fd);
    712   3147   xc151355 			return (dladm_errno2status(errno));
    713   3147   xc151355 		}
    714   3147   xc151355 
    715   3147   xc151355 		if ((nfp = fdopen(nfd, "w")) == NULL) {
    716   3147   xc151355 			(void) close(nfd);
    717   3147   xc151355 			(void) fclose(fp);
    718   3147   xc151355 			(void) unlink(newfile);
    719   3147   xc151355 			i_dladm_unlock_db(lock, lock_fd);
    720   3147   xc151355 			return (dladm_errno2status(errno));
    721   3147   xc151355 		}
    722   3147   xc151355 	}
    723   8453     Anurag 	status = (*process_db)(handle, arg, fp, nfp);
    724   3147   xc151355 	if (!writeop || status != DLADM_STATUS_OK)
    725   3147   xc151355 		goto done;
    726   3147   xc151355 
    727   3147   xc151355 	/*
    728   3147   xc151355 	 * Configuration files need to be owned by the 'dladm' user.
    729   3147   xc151355 	 * If we are invoked by root, the file ownership needs to be fixed.
    730   3147   xc151355 	 */
    731   3147   xc151355 	if (getuid() == 0 || geteuid() == 0) {
    732   6173   yz147064 		if (fchown(nfd, UID_DLADM, GID_SYS) < 0) {
    733   3147   xc151355 			status = dladm_errno2status(errno);
    734   3147   xc151355 			goto done;
    735   3147   xc151355 		}
    736   3147   xc151355 	}
    737   3147   xc151355 
    738   3147   xc151355 	if (fflush(nfp) == EOF) {
    739   3147   xc151355 		status = dladm_errno2status(errno);
    740   3147   xc151355 		goto done;
    741   3147   xc151355 	}
    742   3147   xc151355 	(void) fclose(fp);
    743   3147   xc151355 	(void) fclose(nfp);
    744   3147   xc151355 
    745   3147   xc151355 	if (rename(newfile, file) < 0) {
    746   3147   xc151355 		(void) unlink(newfile);
    747   3147   xc151355 		i_dladm_unlock_db(lock, lock_fd);
    748   3147   xc151355 		return (dladm_errno2status(errno));
    749   3147   xc151355 	}
    750   3147   xc151355 
    751   3147   xc151355 	i_dladm_unlock_db(lock, lock_fd);
    752   3147   xc151355 	return (DLADM_STATUS_OK);
    753   3147   xc151355 
    754   3147   xc151355 done:
    755   3147   xc151355 	if (nfp != NULL) {
    756   3147   xc151355 		(void) fclose(nfp);
    757   3147   xc151355 		if (status != DLADM_STATUS_OK)
    758   3147   xc151355 			(void) unlink(newfile);
    759   3147   xc151355 	}
    760   3147   xc151355 	(void) fclose(fp);
    761   3147   xc151355 	i_dladm_unlock_db(lock, lock_fd);
    762   3147   xc151355 	return (status);
    763   3147   xc151355 }
    764   3147   xc151355 
    765   3147   xc151355 dladm_status_t
    766   3147   xc151355 dladm_set_rootdir(const char *rootdir)
    767   3147   xc151355 {
    768   3147   xc151355 	DIR	*dp;
    769   3147   xc151355 
    770   3147   xc151355 	if (rootdir == NULL || *rootdir != '/' ||
    771   3147   xc151355 	    (dp = opendir(rootdir)) == NULL)
    772   3147   xc151355 		return (DLADM_STATUS_BADARG);
    773   3147   xc151355 
    774   3147   xc151355 	(void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN);
    775   3147   xc151355 	(void) closedir(dp);
    776   3147   xc151355 	return (DLADM_STATUS_OK);
    777   3147   xc151355 }
    778   5895   yz147064 
    779   5895   yz147064 boolean_t
    780   5895   yz147064 dladm_valid_linkname(const char *link)
    781   5895   yz147064 {
    782   5895   yz147064 	size_t		len = strlen(link);
    783   5895   yz147064 	const char	*cp;
    784   5895   yz147064 
    785  10616  Sebastien 	if (len >= MAXLINKNAMELEN)
    786   5895   yz147064 		return (B_FALSE);
    787   5895   yz147064 
    788   5895   yz147064 	/*
    789   5895   yz147064 	 * The link name cannot start with a digit and must end with a digit.
    790   5895   yz147064 	 */
    791   5895   yz147064 	if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0))
    792   5895   yz147064 		return (B_FALSE);
    793   5895   yz147064 
    794   5895   yz147064 	/*
    795   5895   yz147064 	 * The legal characters in a link name are:
    796  10616  Sebastien 	 * alphanumeric (a-z,  A-Z,  0-9), underscore ('_'), and '.'.
    797   5895   yz147064 	 */
    798   5895   yz147064 	for (cp = link; *cp != '\0'; cp++) {
    799  10616  Sebastien 		if ((isalnum(*cp) == 0) && (*cp != '_') && (*cp != '.'))
    800   5895   yz147064 			return (B_FALSE);
    801   5895   yz147064 	}
    802   5895   yz147064 
    803   5895   yz147064 	return (B_TRUE);
    804   5895   yz147064 }
    805   8275       Eric 
    806   8275       Eric /*
    807   8275       Eric  * Convert priority string to a value.
    808   8275       Eric  */
    809   8275       Eric dladm_status_t
    810   8275       Eric dladm_str2pri(char *token, mac_priority_level_t *pri)
    811   8275       Eric {
    812   8275       Eric 	if (strlen(token) == strlen("low") &&
    813   8275       Eric 	    strncasecmp(token, "low", strlen("low")) == 0) {
    814   8275       Eric 		*pri = MPL_LOW;
    815   8275       Eric 	} else if (strlen(token) == strlen("medium") &&
    816   8275       Eric 	    strncasecmp(token, "medium", strlen("medium")) == 0) {
    817   8275       Eric 		*pri = MPL_MEDIUM;
    818   8275       Eric 	} else if (strlen(token) == strlen("high") &&
    819   8275       Eric 	    strncasecmp(token, "high", strlen("high")) == 0) {
    820   8275       Eric 		*pri = MPL_HIGH;
    821   8275       Eric 	} else {
    822   8275       Eric 		return (DLADM_STATUS_BADVAL);
    823   8275       Eric 	}
    824   8275       Eric 	return (DLADM_STATUS_OK);
    825   8275       Eric }
    826   8275       Eric 
    827   8275       Eric /*
    828   8275       Eric  * Convert priority value to a string.
    829   8275       Eric  */
    830   8275       Eric const char *
    831   8275       Eric dladm_pri2str(mac_priority_level_t pri, char *buf)
    832   8275       Eric {
    833   8275       Eric 	const char	*s;
    834   8275       Eric 
    835   8275       Eric 	switch (pri) {
    836   8275       Eric 	case MPL_LOW:
    837   8275       Eric 		s = "low";
    838   8275       Eric 		break;
    839   8275       Eric 	case MPL_MEDIUM:
    840   8275       Eric 		s = "medium";
    841   8275       Eric 		break;
    842   8275       Eric 	case MPL_HIGH:
    843   8275       Eric 		s = "high";
    844   8275       Eric 		break;
    845   8275       Eric 	default:
    846   8275       Eric 		s = "--";
    847   8275       Eric 		break;
    848   8275       Eric 	}
    849   8275       Eric 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
    850   8275       Eric 	return (buf);
    851   8275       Eric }
    852   8275       Eric 
    853  10734       Eric /*
    854  10734       Eric  * Convert protect string to a value.
    855  10734       Eric  */
    856  10734       Eric dladm_status_t
    857  10734       Eric dladm_str2protect(char *token, uint32_t *ptype)
    858  10734       Eric {
    859  10734       Eric 	link_protect_t	*lp;
    860  10734       Eric 	int		i;
    861  10734       Eric 
    862  10734       Eric 	for (i = 0; i < LPTYPES; i++) {
    863  10734       Eric 		lp = &link_protect_types[i];
    864  10734       Eric 		if (strcmp(token, lp->lp_name) == 0) {
    865  10734       Eric 			*ptype = lp->lp_type;
    866  10734       Eric 			return (DLADM_STATUS_OK);
    867  10734       Eric 		}
    868  10734       Eric 	}
    869  10734       Eric 	return (DLADM_STATUS_BADVAL);
    870  10734       Eric }
    871  10734       Eric 
    872  10734       Eric /*
    873  10734       Eric  * Convert protect value to a string.
    874  10734       Eric  */
    875  10734       Eric const char *
    876  10734       Eric dladm_protect2str(uint32_t ptype, char *buf)
    877  10734       Eric {
    878  10734       Eric 	const char	*s = "--";
    879  10734       Eric 	link_protect_t	*lp;
    880  10734       Eric 	int		i;
    881  10734       Eric 
    882  10734       Eric 	for (i = 0; i < LPTYPES; i++) {
    883  10734       Eric 		lp = &link_protect_types[i];
    884  10734       Eric 		if (lp->lp_type == ptype) {
    885  10734       Eric 			s = lp->lp_name;
    886  10734       Eric 			break;
    887  10734       Eric 		}
    888  10734       Eric 	}
    889  10734       Eric 	(void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
    890  10734       Eric 	return (buf);
    891  10734       Eric }
    892  10734       Eric 
    893  10734       Eric /*
    894  10734       Eric  * Convert an IPv4 address to/from a string.
    895  10734       Eric  */
    896  10734       Eric const char *
    897  10734       Eric dladm_ipv4addr2str(void *addr, char *buf)
    898  10734       Eric {
    899  10734       Eric 	if (inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN) == NULL)
    900  10734       Eric 		buf[0] = 0;
    901  10734       Eric 
    902  10734       Eric 	return (buf);
    903  10734       Eric }
    904  10734       Eric 
    905  10734       Eric dladm_status_t
    906  10734       Eric dladm_str2ipv4addr(char *token, void *addr)
    907  10734       Eric {
    908  10734       Eric 	return (inet_pton(AF_INET, token, addr) == 1 ?
    909  10734       Eric 	    DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP);
    910  10734       Eric }
    911  10734       Eric 
    912  10734       Eric /*
    913  10734       Eric  * Find the set bits in a mask.
    914  10734       Eric  * This is used for expanding a bitmask into individual sub-masks
    915  10734       Eric  * which can be used for further processing.
    916  10734       Eric  */
    917  10734       Eric void
    918  10734       Eric dladm_find_setbits32(uint32_t mask, uint32_t *list, uint32_t *cnt)
    919  10734       Eric {
    920  10734       Eric 	int	i, c = 0;
    921  10734       Eric 
    922  10734       Eric 	for (i = 0; i < 32; i++) {
    923  10734       Eric 		if (((1 << i) & mask) != 0)
    924  10734       Eric 			list[c++] = 1 << i;
    925  10734       Eric 	}
    926  10734       Eric 	*cnt = c;
    927  10734       Eric }
    928  10734       Eric 
    929   8275       Eric void
    930   8275       Eric dladm_free_args(dladm_arg_list_t *list)
    931   8275       Eric {
    932   8275       Eric 	if (list != NULL) {
    933   8275       Eric 		free(list->al_buf);
    934   8275       Eric 		free(list);
    935   8275       Eric 	}
    936   8275       Eric }
    937   8275       Eric 
    938   8275       Eric dladm_status_t
    939   8275       Eric dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues)
    940   8275       Eric {
    941   8275       Eric 	dladm_arg_list_t	*list;
    942   8275       Eric 	dladm_arg_info_t	*aip;
    943   8275       Eric 	char			*buf, *curr;
    944   8275       Eric 	int			len, i;
    945   8275       Eric 
    946   9055    Michael 	if (str == NULL)
    947   9055    Michael 		return (DLADM_STATUS_BADVAL);
    948   9055    Michael 
    949   9055    Michael 	if (str[0] == '\0')
    950   9055    Michael 		return (DLADM_STATUS_OK);
    951   9055    Michael 
    952   8275       Eric 	list = malloc(sizeof (dladm_arg_list_t));
    953   8275       Eric 	if (list == NULL)
    954   8275       Eric 		return (dladm_errno2status(errno));
    955   8275       Eric 
    956   8275       Eric 	list->al_count = 0;
    957   8275       Eric 	list->al_buf = buf = strdup(str);
    958   8275       Eric 	if (buf == NULL)
    959   8275       Eric 		return (dladm_errno2status(errno));
    960   8275       Eric 
    961   8275       Eric 	curr = buf;
    962   8275       Eric 	len = strlen(buf);
    963   8275       Eric 	aip = NULL;
    964   8275       Eric 	for (i = 0; i < len; i++) {
    965   8275       Eric 		char		c = buf[i];
    966   8275       Eric 		boolean_t	match = (c == '=' || c == ',');
    967   8275       Eric 
    968   8275       Eric 		if (!match && i != len - 1)
    969   8275       Eric 			continue;
    970   8275       Eric 
    971   8275       Eric 		if (match) {
    972   8275       Eric 			buf[i] = '\0';
    973   8275       Eric 			if (*curr == '\0')
    974   8275       Eric 				goto fail;
    975   8275       Eric 		}
    976   8275       Eric 
    977   8275       Eric 		if (aip != NULL && c != '=') {
    978   8275       Eric 			if (aip->ai_count > DLADM_MAX_ARG_VALS)
    979   8275       Eric 				goto fail;
    980   8275       Eric 
    981   8275       Eric 			if (novalues)
    982   8275       Eric 				goto fail;
    983   8275       Eric 
    984   8275       Eric 			aip->ai_val[aip->ai_count] = curr;
    985   8275       Eric 			aip->ai_count++;
    986   8275       Eric 		} else {
    987   8275       Eric 			if (list->al_count > DLADM_MAX_ARG_VALS)
    988   8275       Eric 				goto fail;
    989   8275       Eric 
    990   8275       Eric 			aip = &list->al_info[list->al_count];
    991   8275       Eric 			aip->ai_name = curr;
    992   8275       Eric 			aip->ai_count = 0;
    993   8275       Eric 			list->al_count++;
    994   8275       Eric 			if (c == ',')
    995   8275       Eric 				aip = NULL;
    996   8275       Eric 		}
    997   8275       Eric 		curr = buf + i + 1;
    998   8275       Eric 	}
    999   8275       Eric 
   1000   8275       Eric 	*listp = list;
   1001   8275       Eric 	return (DLADM_STATUS_OK);
   1002   8275       Eric 
   1003   8275       Eric fail:
   1004   8275       Eric 	dladm_free_args(list);
   1005   8275       Eric 	return (DLADM_STATUS_FAILED);
   1006   8275       Eric }
   1007