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