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> 36*9107Sjames.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 438453SAnurag.Maskey@Sun.COM dladm_status_t 448453SAnurag.Maskey@Sun.COM dladm_open(dladm_handle_t *handle) 458453SAnurag.Maskey@Sun.COM { 468453SAnurag.Maskey@Sun.COM int dld_fd; 478453SAnurag.Maskey@Sun.COM 488453SAnurag.Maskey@Sun.COM if (handle == NULL) 498453SAnurag.Maskey@Sun.COM return (DLADM_STATUS_BADARG); 508453SAnurag.Maskey@Sun.COM 518453SAnurag.Maskey@Sun.COM if ((dld_fd = open(DLD_CONTROL_DEV, O_RDWR)) < 0) 528453SAnurag.Maskey@Sun.COM return (dladm_errno2status(errno)); 538453SAnurag.Maskey@Sun.COM 548453SAnurag.Maskey@Sun.COM /* 558453SAnurag.Maskey@Sun.COM * Don't open DLMGMT_DOOR now. dlmgmtd(1M) is not able to 568453SAnurag.Maskey@Sun.COM * open the door when the dladm handle is opened because the 578453SAnurag.Maskey@Sun.COM * door hasn't been created yet at that time. Thus, we must 588453SAnurag.Maskey@Sun.COM * open it on-demand in dladm_door_fd(). Move the open() 598453SAnurag.Maskey@Sun.COM * to dladm_door_fd() for all cases. 608453SAnurag.Maskey@Sun.COM */ 618453SAnurag.Maskey@Sun.COM 628453SAnurag.Maskey@Sun.COM if ((*handle = malloc(sizeof (struct dladm_handle))) == NULL) { 638453SAnurag.Maskey@Sun.COM (void) close(dld_fd); 648453SAnurag.Maskey@Sun.COM return (DLADM_STATUS_NOMEM); 658453SAnurag.Maskey@Sun.COM } 668453SAnurag.Maskey@Sun.COM 678453SAnurag.Maskey@Sun.COM (*handle)->dld_fd = dld_fd; 688453SAnurag.Maskey@Sun.COM (*handle)->door_fd = -1; 698453SAnurag.Maskey@Sun.COM 708453SAnurag.Maskey@Sun.COM return (DLADM_STATUS_OK); 718453SAnurag.Maskey@Sun.COM } 728453SAnurag.Maskey@Sun.COM 738453SAnurag.Maskey@Sun.COM void 748453SAnurag.Maskey@Sun.COM dladm_close(dladm_handle_t handle) 758453SAnurag.Maskey@Sun.COM { 768453SAnurag.Maskey@Sun.COM if (handle != NULL) { 778453SAnurag.Maskey@Sun.COM (void) close(handle->dld_fd); 788453SAnurag.Maskey@Sun.COM if (handle->door_fd != -1) 798453SAnurag.Maskey@Sun.COM (void) close(handle->door_fd); 808453SAnurag.Maskey@Sun.COM free(handle); 818453SAnurag.Maskey@Sun.COM } 828453SAnurag.Maskey@Sun.COM } 838453SAnurag.Maskey@Sun.COM 848453SAnurag.Maskey@Sun.COM int 858453SAnurag.Maskey@Sun.COM dladm_dld_fd(dladm_handle_t handle) 868453SAnurag.Maskey@Sun.COM { 878453SAnurag.Maskey@Sun.COM return (handle->dld_fd); 888453SAnurag.Maskey@Sun.COM } 898453SAnurag.Maskey@Sun.COM 908453SAnurag.Maskey@Sun.COM /* 918453SAnurag.Maskey@Sun.COM * If DLMGMT_DOOR hasn't been opened in the handle yet, open it. 928453SAnurag.Maskey@Sun.COM */ 938453SAnurag.Maskey@Sun.COM dladm_status_t 948453SAnurag.Maskey@Sun.COM dladm_door_fd(dladm_handle_t handle, int *door_fd) 958453SAnurag.Maskey@Sun.COM { 968453SAnurag.Maskey@Sun.COM int fd; 978453SAnurag.Maskey@Sun.COM 988453SAnurag.Maskey@Sun.COM if (handle->door_fd == -1) { 998453SAnurag.Maskey@Sun.COM if ((fd = open(DLMGMT_DOOR, O_RDONLY)) < 0) 1008453SAnurag.Maskey@Sun.COM return (dladm_errno2status(errno)); 1018453SAnurag.Maskey@Sun.COM handle->door_fd = fd; 1028453SAnurag.Maskey@Sun.COM } 1038453SAnurag.Maskey@Sun.COM *door_fd = handle->door_fd; 1048453SAnurag.Maskey@Sun.COM 1058453SAnurag.Maskey@Sun.COM return (DLADM_STATUS_OK); 1068453SAnurag.Maskey@Sun.COM } 1073147Sxc151355 1083147Sxc151355 const char * 1093147Sxc151355 dladm_status2str(dladm_status_t status, char *buf) 1103147Sxc151355 { 1113147Sxc151355 const char *s; 1123147Sxc151355 1133147Sxc151355 switch (status) { 1143147Sxc151355 case DLADM_STATUS_OK: 1153147Sxc151355 s = "ok"; 1163147Sxc151355 break; 1173147Sxc151355 case DLADM_STATUS_BADARG: 1183147Sxc151355 s = "invalid argument"; 1193147Sxc151355 break; 1203147Sxc151355 case DLADM_STATUS_FAILED: 1213147Sxc151355 s = "operation failed"; 1223147Sxc151355 break; 1233147Sxc151355 case DLADM_STATUS_TOOSMALL: 1243147Sxc151355 s = "buffer size too small"; 1253147Sxc151355 break; 1263147Sxc151355 case DLADM_STATUS_NOTSUP: 1273147Sxc151355 s = "operation not supported"; 1283147Sxc151355 break; 1293147Sxc151355 case DLADM_STATUS_NOTFOUND: 1303147Sxc151355 s = "object not found"; 1313147Sxc151355 break; 1323147Sxc151355 case DLADM_STATUS_BADVAL: 1333147Sxc151355 s = "invalid value"; 1343147Sxc151355 break; 1353147Sxc151355 case DLADM_STATUS_NOMEM: 1363147Sxc151355 s = "insufficient memory"; 1373147Sxc151355 break; 1383147Sxc151355 case DLADM_STATUS_EXIST: 1393147Sxc151355 s = "object already exists"; 1403147Sxc151355 break; 1413147Sxc151355 case DLADM_STATUS_LINKINVAL: 1423147Sxc151355 s = "invalid link"; 1433147Sxc151355 break; 1443147Sxc151355 case DLADM_STATUS_PROPRDONLY: 1453147Sxc151355 s = "read-only property"; 1463147Sxc151355 break; 1473147Sxc151355 case DLADM_STATUS_BADVALCNT: 1483147Sxc151355 s = "invalid number of values"; 1493147Sxc151355 break; 1503147Sxc151355 case DLADM_STATUS_DBNOTFOUND: 1513147Sxc151355 s = "database not found"; 1523147Sxc151355 break; 1533147Sxc151355 case DLADM_STATUS_DENIED: 1543147Sxc151355 s = "permission denied"; 1553147Sxc151355 break; 1563147Sxc151355 case DLADM_STATUS_IOERR: 1573147Sxc151355 s = "I/O error"; 1583147Sxc151355 break; 1593448Sdh155122 case DLADM_STATUS_TEMPONLY: 1608275SEric Cheng s = "change cannot be persistent"; 1613448Sdh155122 break; 1623871Syz147064 case DLADM_STATUS_TIMEDOUT: 1633871Syz147064 s = "operation timed out"; 1643871Syz147064 break; 1653871Syz147064 case DLADM_STATUS_ISCONN: 1663871Syz147064 s = "already connected"; 1673871Syz147064 break; 1683871Syz147064 case DLADM_STATUS_NOTCONN: 1693871Syz147064 s = "not connected"; 1703871Syz147064 break; 1713871Syz147064 case DLADM_STATUS_REPOSITORYINVAL: 1723871Syz147064 s = "invalid configuration repository"; 1733871Syz147064 break; 1743871Syz147064 case DLADM_STATUS_MACADDRINVAL: 1753871Syz147064 s = "invalid MAC address"; 1763871Syz147064 break; 1773871Syz147064 case DLADM_STATUS_KEYINVAL: 1783871Syz147064 s = "invalid key"; 1793871Syz147064 break; 1805084Sjohnlev case DLADM_STATUS_INVALIDMACADDRLEN: 1815084Sjohnlev s = "invalid MAC address length"; 1825084Sjohnlev break; 1835084Sjohnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 1845084Sjohnlev s = "invalid MAC address type"; 1855084Sjohnlev break; 1865895Syz147064 case DLADM_STATUS_LINKBUSY: 1875895Syz147064 s = "link busy"; 1885895Syz147064 break; 1895895Syz147064 case DLADM_STATUS_VIDINVAL: 1905895Syz147064 s = "invalid VLAN identifier"; 1915084Sjohnlev break; 1925895Syz147064 case DLADM_STATUS_TRYAGAIN: 1935895Syz147064 s = "try again later"; 1945084Sjohnlev break; 1955895Syz147064 case DLADM_STATUS_NONOTIF: 1965895Syz147064 s = "link notification is not supported"; 1975084Sjohnlev break; 1988275SEric Cheng case DLADM_STATUS_BADTIMEVAL: 1998275SEric Cheng s = "invalid time range"; 2008275SEric Cheng break; 2018275SEric Cheng case DLADM_STATUS_INVALIDMACADDR: 2028275SEric Cheng s = "invalid MAC address value"; 2038275SEric Cheng break; 2048275SEric Cheng case DLADM_STATUS_INVALIDMACADDRNIC: 2058275SEric Cheng s = "MAC address reserved for use by underlying data-link"; 2068275SEric Cheng break; 2078275SEric Cheng case DLADM_STATUS_INVALIDMACADDRINUSE: 2088275SEric Cheng s = "MAC address is already in use"; 2098275SEric Cheng break; 2108275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTINVALID: 2118275SEric Cheng s = "invalid factory MAC address slot"; 2128275SEric Cheng break; 2138275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTUSED: 2148275SEric Cheng s = "factory MAC address slot already used"; 2158275SEric Cheng break; 2168275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTALLUSED: 2178275SEric Cheng s = "all factory MAC address slots are in use"; 2188275SEric Cheng break; 2198275SEric Cheng case DLADM_STATUS_MACFACTORYNOTSUP: 2208275SEric Cheng s = "factory MAC address slots not supported"; 2218275SEric Cheng break; 2228275SEric Cheng case DLADM_STATUS_INVALIDMACPREFIX: 2238275SEric Cheng s = "Invalid MAC address prefix value"; 2248275SEric Cheng break; 2258275SEric Cheng case DLADM_STATUS_INVALIDMACPREFIXLEN: 2268275SEric Cheng s = "Invalid MAC address prefix length"; 2278275SEric Cheng break; 2288275SEric Cheng case DLADM_STATUS_CPUMAX: 2298275SEric Cheng s = "non-existent processor ID"; 2308275SEric Cheng break; 2318275SEric Cheng case DLADM_STATUS_CPUERR: 2328275SEric Cheng s = "could not determine processor status"; 2338275SEric Cheng break; 2348275SEric Cheng case DLADM_STATUS_CPUNOTONLINE: 2358275SEric Cheng s = "processor not online"; 2368275SEric Cheng break; 2378275SEric Cheng case DLADM_STATUS_DB_NOTFOUND: 2388275SEric Cheng s = "database not found"; 2398275SEric Cheng break; 2408275SEric Cheng case DLADM_STATUS_DB_PARSE_ERR: 2418275SEric Cheng s = "database parse error"; 2428275SEric Cheng break; 2438275SEric Cheng case DLADM_STATUS_PROP_PARSE_ERR: 2448275SEric Cheng s = "property parse error"; 2458275SEric Cheng break; 2468275SEric Cheng case DLADM_STATUS_ATTR_PARSE_ERR: 2478275SEric Cheng s = "attribute parse error"; 2488275SEric Cheng break; 2498275SEric Cheng case DLADM_STATUS_FLOW_DB_ERR: 2508275SEric Cheng s = "flow database error"; 2518275SEric Cheng break; 2528275SEric Cheng case DLADM_STATUS_FLOW_DB_OPEN_ERR: 2538275SEric Cheng s = "flow database open error"; 2548275SEric Cheng break; 2558275SEric Cheng case DLADM_STATUS_FLOW_DB_PARSE_ERR: 2568275SEric Cheng s = "flow database parse error"; 2578275SEric Cheng break; 2588275SEric Cheng case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR: 2598275SEric Cheng s = "flow property database parse error"; 2608275SEric Cheng break; 2618275SEric Cheng case DLADM_STATUS_FLOW_ADD_ERR: 2628275SEric Cheng s = "flow add error"; 2638275SEric Cheng break; 2648275SEric Cheng case DLADM_STATUS_FLOW_WALK_ERR: 2658275SEric Cheng s = "flow walk error"; 2668275SEric Cheng break; 2678275SEric Cheng case DLADM_STATUS_FLOW_IDENTICAL: 2688275SEric Cheng s = "a flow with identical attributes exists"; 2698275SEric Cheng break; 2708275SEric Cheng case DLADM_STATUS_FLOW_INCOMPATIBLE: 2718275SEric Cheng s = "flow(s) with incompatible attributes exists"; 2728275SEric Cheng break; 2738275SEric Cheng case DLADM_STATUS_FLOW_EXISTS: 2748275SEric Cheng s = "link still has flows"; 2758275SEric Cheng break; 2768275SEric Cheng case DLADM_STATUS_PERSIST_FLOW_EXISTS: 2778275SEric Cheng s = "persistent flow with the same name exists"; 2788275SEric Cheng break; 2798275SEric Cheng case DLADM_STATUS_INVALID_IP: 2808275SEric Cheng s = "invalid IP address"; 2818275SEric Cheng break; 2828275SEric Cheng case DLADM_STATUS_INVALID_PREFIXLEN: 2838275SEric Cheng s = "invalid IP prefix length"; 2848275SEric Cheng break; 2858275SEric Cheng case DLADM_STATUS_INVALID_PROTOCOL: 2868275SEric Cheng s = "invalid IP protocol"; 2878275SEric Cheng break; 2888275SEric Cheng case DLADM_STATUS_INVALID_PORT: 2898275SEric Cheng s = "invalid port number"; 2908275SEric Cheng break; 2918275SEric Cheng case DLADM_STATUS_INVALID_DSF: 2928275SEric Cheng s = "invalid dsfield"; 2938275SEric Cheng break; 2948275SEric Cheng case DLADM_STATUS_INVALID_DSFMASK: 2958275SEric Cheng s = "invalid dsfield mask"; 2968275SEric Cheng break; 2978275SEric Cheng case DLADM_STATUS_INVALID_MACMARGIN: 2988275SEric Cheng s = "MTU check failed, use lower MTU or -f option"; 2998275SEric Cheng break; 3008275SEric Cheng case DLADM_STATUS_BADPROP: 3018275SEric Cheng s = "invalid property"; 3028275SEric Cheng break; 3038275SEric Cheng case DLADM_STATUS_MINMAXBW: 3048275SEric Cheng s = "minimum value for maxbw is 1.2M"; 3058275SEric Cheng break; 3068275SEric Cheng case DLADM_STATUS_NO_HWRINGS: 3078275SEric Cheng s = "request hw rings failed"; 3088275SEric Cheng break; 3093147Sxc151355 default: 3103184Smeem s = "<unknown error>"; 3113184Smeem break; 3123147Sxc151355 } 3133184Smeem (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 3143147Sxc151355 return (buf); 3153147Sxc151355 } 3163147Sxc151355 3173147Sxc151355 /* 3183147Sxc151355 * Convert a unix errno to a dladm_status_t. 3193147Sxc151355 * We only convert errnos that are likely to be encountered. All others 3203147Sxc151355 * are mapped to DLADM_STATUS_FAILED. 3213147Sxc151355 */ 3223147Sxc151355 dladm_status_t 3233147Sxc151355 dladm_errno2status(int err) 3243147Sxc151355 { 3253147Sxc151355 switch (err) { 3265903Ssowmini case 0: 3275903Ssowmini return (DLADM_STATUS_OK); 3283147Sxc151355 case EINVAL: 3293147Sxc151355 return (DLADM_STATUS_BADARG); 3303147Sxc151355 case EEXIST: 3313147Sxc151355 return (DLADM_STATUS_EXIST); 3323147Sxc151355 case ENOENT: 3333147Sxc151355 return (DLADM_STATUS_NOTFOUND); 3343147Sxc151355 case ENOSPC: 3353147Sxc151355 return (DLADM_STATUS_TOOSMALL); 3363147Sxc151355 case ENOMEM: 3373147Sxc151355 return (DLADM_STATUS_NOMEM); 3383147Sxc151355 case ENOTSUP: 3393147Sxc151355 return (DLADM_STATUS_NOTSUP); 3405895Syz147064 case ENETDOWN: 3415895Syz147064 return (DLADM_STATUS_NONOTIF); 3423147Sxc151355 case EACCES: 3437408SSebastien.Roy@Sun.COM case EPERM: 3443147Sxc151355 return (DLADM_STATUS_DENIED); 3453147Sxc151355 case EIO: 3463147Sxc151355 return (DLADM_STATUS_IOERR); 3475084Sjohnlev case EBUSY: 3485895Syz147064 return (DLADM_STATUS_LINKBUSY); 3495895Syz147064 case EAGAIN: 3505895Syz147064 return (DLADM_STATUS_TRYAGAIN); 3518275SEric Cheng case ENOTEMPTY: 3528275SEric Cheng return (DLADM_STATUS_FLOW_EXISTS); 3538275SEric Cheng case EOPNOTSUPP: 3548275SEric Cheng return (DLADM_STATUS_FLOW_INCOMPATIBLE); 3558275SEric Cheng case EALREADY: 3568275SEric Cheng return (DLADM_STATUS_FLOW_IDENTICAL); 3573147Sxc151355 default: 3583147Sxc151355 return (DLADM_STATUS_FAILED); 3593147Sxc151355 } 3603147Sxc151355 } 3613147Sxc151355 3629055SMichael.Lim@Sun.COM boolean_t 3639055SMichael.Lim@Sun.COM dladm_str2interval(char *oarg, uint32_t *interval) 3649055SMichael.Lim@Sun.COM { 3659055SMichael.Lim@Sun.COM int val; 3669055SMichael.Lim@Sun.COM char *endp = NULL; 3679055SMichael.Lim@Sun.COM 3689055SMichael.Lim@Sun.COM errno = 0; 3699055SMichael.Lim@Sun.COM val = strtol(oarg, &endp, 10); 3709055SMichael.Lim@Sun.COM if (errno != 0 || val <= 0 || *endp != '\0') 3719055SMichael.Lim@Sun.COM return (B_FALSE); 3729055SMichael.Lim@Sun.COM 3739055SMichael.Lim@Sun.COM *interval = val; 3749055SMichael.Lim@Sun.COM 3759055SMichael.Lim@Sun.COM return (B_TRUE); 3769055SMichael.Lim@Sun.COM } 3779055SMichael.Lim@Sun.COM 3788275SEric Cheng dladm_status_t 3798275SEric Cheng dladm_str2bw(char *oarg, uint64_t *bw) 3808275SEric Cheng { 3818275SEric Cheng char *endp = NULL; 3828275SEric Cheng int64_t n; 3838275SEric Cheng int mult = 1; 3848275SEric Cheng 3858275SEric Cheng n = strtoull(oarg, &endp, 10); 3868275SEric Cheng 3878275SEric Cheng if ((errno != 0) || (strlen(endp) > 1)) 3888275SEric Cheng return (DLADM_STATUS_BADARG); 3898275SEric Cheng 3908275SEric Cheng if (n < 0) 3918275SEric Cheng return (DLADM_STATUS_BADVAL); 3928275SEric Cheng 3938275SEric Cheng switch (*endp) { 3948275SEric Cheng case 'k': 3958275SEric Cheng case 'K': 3968275SEric Cheng mult = 1000; 3978275SEric Cheng break; 3988275SEric Cheng case 'm': 3998275SEric Cheng case 'M': 4008275SEric Cheng case '\0': 4018275SEric Cheng mult = 1000000; 4028275SEric Cheng break; 4038275SEric Cheng case 'g': 4048275SEric Cheng case 'G': 4058275SEric Cheng mult = 1000000000; 4068275SEric Cheng break; 4078275SEric Cheng case '%': 4088275SEric Cheng /* 4098275SEric Cheng * percentages not supported for now, 4108275SEric Cheng * see RFE 6540675 4118275SEric Cheng */ 4128275SEric Cheng return (DLADM_STATUS_NOTSUP); 4138275SEric Cheng default: 4148275SEric Cheng return (DLADM_STATUS_BADVAL); 4158275SEric Cheng } 4168275SEric Cheng 4178275SEric Cheng *bw = n * mult; 4188275SEric Cheng 4198275SEric Cheng /* check for overflow */ 4208275SEric Cheng if (*bw / mult != n) 4218275SEric Cheng return (DLADM_STATUS_BADARG); 4228275SEric Cheng 4238275SEric Cheng return (DLADM_STATUS_OK); 4248275SEric Cheng } 4258275SEric Cheng 4268275SEric Cheng /* 4278275SEric Cheng * Convert bandwidth in bps to a string in mpbs. For values greater 4288275SEric Cheng * than 1mbps or 1000000, print a whole mbps value. For values that 4298275SEric Cheng * have fractional Mbps in whole Kbps , print the bandwidth in a manner 4308275SEric Cheng * simlilar to a floating point format. 4318275SEric Cheng * 4328275SEric Cheng * bps string 4338275SEric Cheng * 0 0 4348275SEric Cheng * 100 0 4358275SEric Cheng * 2000 0.002 4368275SEric Cheng * 431000 0.431 4378275SEric Cheng * 1000000 1 4388275SEric Cheng * 1030000 1.030 4398275SEric Cheng * 100000000 100 4408275SEric Cheng */ 4418275SEric Cheng const char * 4428275SEric Cheng dladm_bw2str(int64_t bw, char *buf) 4438275SEric Cheng { 4448275SEric Cheng int kbps, mbps; 4458275SEric Cheng 4468275SEric Cheng kbps = (bw%1000000)/1000; 4478275SEric Cheng mbps = bw/1000000; 4488275SEric Cheng if (kbps != 0) { 4498275SEric Cheng if (mbps == 0) 4508275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 4518275SEric Cheng else 4528275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 4538275SEric Cheng kbps); 4548275SEric Cheng } else { 4558275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 4568275SEric Cheng } 4578275SEric Cheng 4588275SEric Cheng return (buf); 4598275SEric Cheng } 4608275SEric Cheng 4615895Syz147064 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 4623147Sxc151355 4633147Sxc151355 static int 4643147Sxc151355 i_dladm_lock_db(const char *lock_file, short type) 4653147Sxc151355 { 4663147Sxc151355 int lock_fd; 4675895Syz147064 struct flock lock; 4683147Sxc151355 4693147Sxc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 4703147Sxc151355 LOCK_DB_PERMS)) < 0) 4713147Sxc151355 return (-1); 4723147Sxc151355 4733147Sxc151355 lock.l_type = type; 4743147Sxc151355 lock.l_whence = SEEK_SET; 4753147Sxc151355 lock.l_start = 0; 4763147Sxc151355 lock.l_len = 0; 4773147Sxc151355 4783147Sxc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 4793147Sxc151355 int err = errno; 4803147Sxc151355 4813147Sxc151355 (void) close(lock_fd); 4823147Sxc151355 (void) unlink(lock_file); 4833147Sxc151355 errno = err; 4843147Sxc151355 return (-1); 4853147Sxc151355 } 4863147Sxc151355 return (lock_fd); 4873147Sxc151355 } 4883147Sxc151355 4893147Sxc151355 static void 4903147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd) 4913147Sxc151355 { 4923147Sxc151355 struct flock lock; 4933147Sxc151355 4943147Sxc151355 if (fd < 0) 4953147Sxc151355 return; 4963147Sxc151355 4973147Sxc151355 lock.l_type = F_UNLCK; 4983147Sxc151355 lock.l_whence = SEEK_SET; 4993147Sxc151355 lock.l_start = 0; 5003147Sxc151355 lock.l_len = 0; 5013147Sxc151355 5023147Sxc151355 (void) fcntl(fd, F_SETLKW, &lock); 5033147Sxc151355 (void) close(fd); 5043147Sxc151355 (void) unlink(lock_file); 5053147Sxc151355 } 5063147Sxc151355 5075895Syz147064 /* 5085895Syz147064 * Given a link class, returns its class string. 5095895Syz147064 */ 5105895Syz147064 const char * 5115895Syz147064 dladm_class2str(datalink_class_t class, char *buf) 5125895Syz147064 { 5135895Syz147064 const char *s; 5145895Syz147064 5155895Syz147064 switch (class) { 5165895Syz147064 case DATALINK_CLASS_PHYS: 5175895Syz147064 s = "phys"; 5185895Syz147064 break; 5195895Syz147064 case DATALINK_CLASS_VLAN: 5205895Syz147064 s = "vlan"; 5215895Syz147064 break; 5225895Syz147064 case DATALINK_CLASS_AGGR: 5235895Syz147064 s = "aggr"; 5245895Syz147064 break; 5255895Syz147064 case DATALINK_CLASS_VNIC: 5265895Syz147064 s = "vnic"; 5275895Syz147064 break; 5288275SEric Cheng case DATALINK_CLASS_ETHERSTUB: 5298275SEric Cheng s = "etherstub"; 5308275SEric Cheng break; 5315895Syz147064 default: 5325895Syz147064 s = "unknown"; 5335895Syz147064 break; 5345895Syz147064 } 5355895Syz147064 5365895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 5375895Syz147064 return (buf); 5385895Syz147064 } 5395895Syz147064 5405895Syz147064 /* 5415895Syz147064 * Given a physical link media type, returns its media type string. 5425895Syz147064 */ 5435895Syz147064 const char * 5445895Syz147064 dladm_media2str(uint32_t media, char *buf) 5455895Syz147064 { 5465895Syz147064 const char *s; 5475895Syz147064 5485895Syz147064 switch (media) { 5495895Syz147064 case DL_ETHER: 5505895Syz147064 s = "Ethernet"; 5515895Syz147064 break; 5525895Syz147064 case DL_WIFI: 5535895Syz147064 s = "WiFi"; 5545895Syz147064 break; 5555895Syz147064 case DL_IB: 5565895Syz147064 s = "Infiniband"; 5575895Syz147064 break; 5585895Syz147064 case DL_IPV4: 5595895Syz147064 s = "IPv4Tunnel"; 5605895Syz147064 break; 5615895Syz147064 case DL_IPV6: 5625895Syz147064 s = "IPv6Tunnel"; 5635895Syz147064 break; 5645895Syz147064 case DL_CSMACD: 5655895Syz147064 s = "CSMA/CD"; 5665895Syz147064 break; 5675895Syz147064 case DL_TPB: 5685895Syz147064 s = "TokenBus"; 5695895Syz147064 break; 5705895Syz147064 case DL_TPR: 5715895Syz147064 s = "TokenRing"; 5725895Syz147064 break; 5735895Syz147064 case DL_METRO: 5745895Syz147064 s = "MetroNet"; 5755895Syz147064 break; 5765895Syz147064 case DL_HDLC: 5775895Syz147064 s = "HDLC"; 5785895Syz147064 break; 5795895Syz147064 case DL_CHAR: 5805895Syz147064 s = "SyncCharacter"; 5815895Syz147064 break; 5825895Syz147064 case DL_CTCA: 5835895Syz147064 s = "CTCA"; 5845895Syz147064 break; 5855895Syz147064 case DL_FDDI: 5865895Syz147064 s = "FDDI"; 5875895Syz147064 break; 5885895Syz147064 case DL_FC: 5895895Syz147064 s = "FiberChannel"; 5905895Syz147064 break; 5915895Syz147064 case DL_ATM: 5925895Syz147064 s = "ATM"; 5935895Syz147064 break; 5945895Syz147064 case DL_IPATM: 5955895Syz147064 s = "ATM(ClassicIP)"; 5965895Syz147064 break; 5975895Syz147064 case DL_X25: 5985895Syz147064 s = "X.25"; 5995895Syz147064 break; 6005895Syz147064 case DL_IPX25: 6015895Syz147064 s = "X.25(ClassicIP)"; 6025895Syz147064 break; 6035895Syz147064 case DL_ISDN: 6045895Syz147064 s = "ISDN"; 6055895Syz147064 break; 6065895Syz147064 case DL_HIPPI: 6075895Syz147064 s = "HIPPI"; 6085895Syz147064 break; 6095895Syz147064 case DL_100VG: 6105895Syz147064 s = "100BaseVGEthernet"; 6115895Syz147064 break; 6125895Syz147064 case DL_100VGTPR: 6135895Syz147064 s = "100BaseVGTokenRing"; 6145895Syz147064 break; 6155895Syz147064 case DL_ETH_CSMA: 6165895Syz147064 s = "IEEE802.3"; 6175895Syz147064 break; 6185895Syz147064 case DL_100BT: 6195895Syz147064 s = "100BaseT"; 6205895Syz147064 break; 6215895Syz147064 case DL_FRAME: 6225895Syz147064 s = "FrameRelay"; 6235895Syz147064 break; 6245895Syz147064 case DL_MPFRAME: 6255895Syz147064 s = "MPFrameRelay"; 6265895Syz147064 break; 6275895Syz147064 case DL_ASYNC: 6285895Syz147064 s = "AsyncCharacter"; 6295895Syz147064 break; 6308023SPhil.Kirk@Sun.COM case DL_IPNET: 6318023SPhil.Kirk@Sun.COM s = "IPNET"; 6328023SPhil.Kirk@Sun.COM break; 6335895Syz147064 default: 6345895Syz147064 s = "--"; 6355895Syz147064 break; 6365895Syz147064 } 6375895Syz147064 6385895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 6395895Syz147064 return (buf); 6405895Syz147064 } 6415895Syz147064 6423147Sxc151355 dladm_status_t 6438453SAnurag.Maskey@Sun.COM i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms, 6448453SAnurag.Maskey@Sun.COM dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *), 6453147Sxc151355 void *arg, boolean_t writeop) 6463147Sxc151355 { 6473147Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 6483147Sxc151355 FILE *fp, *nfp = NULL; 6493147Sxc151355 char lock[MAXPATHLEN]; 6503147Sxc151355 char file[MAXPATHLEN]; 6513147Sxc151355 char newfile[MAXPATHLEN]; 6523147Sxc151355 char *db_basename; 6533147Sxc151355 int nfd, lock_fd; 6543147Sxc151355 6553147Sxc151355 /* 6563147Sxc151355 * If we are called from a boot script such as net-physical, 6573147Sxc151355 * it's quite likely that the root fs is still not writable. 6583147Sxc151355 * For this case, it's ok for the lock creation to fail since 6593147Sxc151355 * no one else could be accessing our configuration file. 6603147Sxc151355 */ 6613147Sxc151355 db_basename = strrchr(db_file, '/'); 6623147Sxc151355 if (db_basename == NULL || db_basename[1] == '\0') 6633147Sxc151355 return (dladm_errno2status(EINVAL)); 6643147Sxc151355 db_basename++; 6653147Sxc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 6663147Sxc151355 if ((lock_fd = i_dladm_lock_db 6673147Sxc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 6683147Sxc151355 return (dladm_errno2status(errno)); 6693147Sxc151355 6703147Sxc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 6713147Sxc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 6723147Sxc151355 int err = errno; 6733147Sxc151355 6743147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6753147Sxc151355 if (err == ENOENT) 6763147Sxc151355 return (DLADM_STATUS_DBNOTFOUND); 6773147Sxc151355 6783147Sxc151355 return (dladm_errno2status(err)); 6793147Sxc151355 } 6803147Sxc151355 6813147Sxc151355 if (writeop) { 6823147Sxc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 6833147Sxc151355 dladm_rootdir, db_file); 6843147Sxc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 6853147Sxc151355 db_perms)) < 0) { 6863147Sxc151355 (void) fclose(fp); 6873147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6883147Sxc151355 return (dladm_errno2status(errno)); 6893147Sxc151355 } 6903147Sxc151355 6913147Sxc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 6923147Sxc151355 (void) close(nfd); 6933147Sxc151355 (void) fclose(fp); 6943147Sxc151355 (void) unlink(newfile); 6953147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6963147Sxc151355 return (dladm_errno2status(errno)); 6973147Sxc151355 } 6983147Sxc151355 } 6998453SAnurag.Maskey@Sun.COM status = (*process_db)(handle, arg, fp, nfp); 7003147Sxc151355 if (!writeop || status != DLADM_STATUS_OK) 7013147Sxc151355 goto done; 7023147Sxc151355 7033147Sxc151355 /* 7043147Sxc151355 * Configuration files need to be owned by the 'dladm' user. 7053147Sxc151355 * If we are invoked by root, the file ownership needs to be fixed. 7063147Sxc151355 */ 7073147Sxc151355 if (getuid() == 0 || geteuid() == 0) { 7086173Syz147064 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 7093147Sxc151355 status = dladm_errno2status(errno); 7103147Sxc151355 goto done; 7113147Sxc151355 } 7123147Sxc151355 } 7133147Sxc151355 7143147Sxc151355 if (fflush(nfp) == EOF) { 7153147Sxc151355 status = dladm_errno2status(errno); 7163147Sxc151355 goto done; 7173147Sxc151355 } 7183147Sxc151355 (void) fclose(fp); 7193147Sxc151355 (void) fclose(nfp); 7203147Sxc151355 7213147Sxc151355 if (rename(newfile, file) < 0) { 7223147Sxc151355 (void) unlink(newfile); 7233147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 7243147Sxc151355 return (dladm_errno2status(errno)); 7253147Sxc151355 } 7263147Sxc151355 7273147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 7283147Sxc151355 return (DLADM_STATUS_OK); 7293147Sxc151355 7303147Sxc151355 done: 7313147Sxc151355 if (nfp != NULL) { 7323147Sxc151355 (void) fclose(nfp); 7333147Sxc151355 if (status != DLADM_STATUS_OK) 7343147Sxc151355 (void) unlink(newfile); 7353147Sxc151355 } 7363147Sxc151355 (void) fclose(fp); 7373147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 7383147Sxc151355 return (status); 7393147Sxc151355 } 7403147Sxc151355 7413147Sxc151355 dladm_status_t 7423147Sxc151355 dladm_set_rootdir(const char *rootdir) 7433147Sxc151355 { 7443147Sxc151355 DIR *dp; 7453147Sxc151355 7463147Sxc151355 if (rootdir == NULL || *rootdir != '/' || 7473147Sxc151355 (dp = opendir(rootdir)) == NULL) 7483147Sxc151355 return (DLADM_STATUS_BADARG); 7493147Sxc151355 7503147Sxc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 7513147Sxc151355 (void) closedir(dp); 7523147Sxc151355 return (DLADM_STATUS_OK); 7533147Sxc151355 } 7545895Syz147064 7555895Syz147064 boolean_t 7565895Syz147064 dladm_valid_linkname(const char *link) 7575895Syz147064 { 7585895Syz147064 size_t len = strlen(link); 7595895Syz147064 const char *cp; 7605895Syz147064 7615895Syz147064 if (len + 1 >= MAXLINKNAMELEN) 7625895Syz147064 return (B_FALSE); 7635895Syz147064 7645895Syz147064 /* 7655895Syz147064 * The link name cannot start with a digit and must end with a digit. 7665895Syz147064 */ 7675895Syz147064 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 7685895Syz147064 return (B_FALSE); 7695895Syz147064 7705895Syz147064 /* 7715895Syz147064 * The legal characters in a link name are: 7725895Syz147064 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 7735895Syz147064 */ 7745895Syz147064 for (cp = link; *cp != '\0'; cp++) { 7755895Syz147064 if ((isalnum(*cp) == 0) && (*cp != '_')) 7765895Syz147064 return (B_FALSE); 7775895Syz147064 } 7785895Syz147064 7795895Syz147064 return (B_TRUE); 7805895Syz147064 } 7818275SEric Cheng 7828275SEric Cheng /* 7838275SEric Cheng * Convert priority string to a value. 7848275SEric Cheng */ 7858275SEric Cheng dladm_status_t 7868275SEric Cheng dladm_str2pri(char *token, mac_priority_level_t *pri) 7878275SEric Cheng { 7888275SEric Cheng if (strlen(token) == strlen("low") && 7898275SEric Cheng strncasecmp(token, "low", strlen("low")) == 0) { 7908275SEric Cheng *pri = MPL_LOW; 7918275SEric Cheng } else if (strlen(token) == strlen("medium") && 7928275SEric Cheng strncasecmp(token, "medium", strlen("medium")) == 0) { 7938275SEric Cheng *pri = MPL_MEDIUM; 7948275SEric Cheng } else if (strlen(token) == strlen("high") && 7958275SEric Cheng strncasecmp(token, "high", strlen("high")) == 0) { 7968275SEric Cheng *pri = MPL_HIGH; 7978275SEric Cheng } else { 7988275SEric Cheng return (DLADM_STATUS_BADVAL); 7998275SEric Cheng } 8008275SEric Cheng return (DLADM_STATUS_OK); 8018275SEric Cheng } 8028275SEric Cheng 8038275SEric Cheng /* 8048275SEric Cheng * Convert priority value to a string. 8058275SEric Cheng */ 8068275SEric Cheng const char * 8078275SEric Cheng dladm_pri2str(mac_priority_level_t pri, char *buf) 8088275SEric Cheng { 8098275SEric Cheng const char *s; 8108275SEric Cheng 8118275SEric Cheng switch (pri) { 8128275SEric Cheng case MPL_LOW: 8138275SEric Cheng s = "low"; 8148275SEric Cheng break; 8158275SEric Cheng case MPL_MEDIUM: 8168275SEric Cheng s = "medium"; 8178275SEric Cheng break; 8188275SEric Cheng case MPL_HIGH: 8198275SEric Cheng s = "high"; 8208275SEric Cheng break; 8218275SEric Cheng default: 8228275SEric Cheng s = "--"; 8238275SEric Cheng break; 8248275SEric Cheng } 8258275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 8268275SEric Cheng return (buf); 8278275SEric Cheng } 8288275SEric Cheng 8298275SEric Cheng void 8308275SEric Cheng dladm_free_args(dladm_arg_list_t *list) 8318275SEric Cheng { 8328275SEric Cheng if (list != NULL) { 8338275SEric Cheng free(list->al_buf); 8348275SEric Cheng free(list); 8358275SEric Cheng } 8368275SEric Cheng } 8378275SEric Cheng 8388275SEric Cheng dladm_status_t 8398275SEric Cheng dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 8408275SEric Cheng { 8418275SEric Cheng dladm_arg_list_t *list; 8428275SEric Cheng dladm_arg_info_t *aip; 8438275SEric Cheng char *buf, *curr; 8448275SEric Cheng int len, i; 8458275SEric Cheng 8469055SMichael.Lim@Sun.COM if (str == NULL) 8479055SMichael.Lim@Sun.COM return (DLADM_STATUS_BADVAL); 8489055SMichael.Lim@Sun.COM 8499055SMichael.Lim@Sun.COM if (str[0] == '\0') 8509055SMichael.Lim@Sun.COM return (DLADM_STATUS_OK); 8519055SMichael.Lim@Sun.COM 8528275SEric Cheng list = malloc(sizeof (dladm_arg_list_t)); 8538275SEric Cheng if (list == NULL) 8548275SEric Cheng return (dladm_errno2status(errno)); 8558275SEric Cheng 8568275SEric Cheng list->al_count = 0; 8578275SEric Cheng list->al_buf = buf = strdup(str); 8588275SEric Cheng if (buf == NULL) 8598275SEric Cheng return (dladm_errno2status(errno)); 8608275SEric Cheng 8618275SEric Cheng curr = buf; 8628275SEric Cheng len = strlen(buf); 8638275SEric Cheng aip = NULL; 8648275SEric Cheng for (i = 0; i < len; i++) { 8658275SEric Cheng char c = buf[i]; 8668275SEric Cheng boolean_t match = (c == '=' || c == ','); 8678275SEric Cheng 8688275SEric Cheng if (!match && i != len - 1) 8698275SEric Cheng continue; 8708275SEric Cheng 8718275SEric Cheng if (match) { 8728275SEric Cheng buf[i] = '\0'; 8738275SEric Cheng if (*curr == '\0') 8748275SEric Cheng goto fail; 8758275SEric Cheng } 8768275SEric Cheng 8778275SEric Cheng if (aip != NULL && c != '=') { 8788275SEric Cheng if (aip->ai_count > DLADM_MAX_ARG_VALS) 8798275SEric Cheng goto fail; 8808275SEric Cheng 8818275SEric Cheng if (novalues) 8828275SEric Cheng goto fail; 8838275SEric Cheng 8848275SEric Cheng aip->ai_val[aip->ai_count] = curr; 8858275SEric Cheng aip->ai_count++; 8868275SEric Cheng } else { 8878275SEric Cheng if (list->al_count > DLADM_MAX_ARG_VALS) 8888275SEric Cheng goto fail; 8898275SEric Cheng 8908275SEric Cheng aip = &list->al_info[list->al_count]; 8918275SEric Cheng aip->ai_name = curr; 8928275SEric Cheng aip->ai_count = 0; 8938275SEric Cheng list->al_count++; 8948275SEric Cheng if (c == ',') 8958275SEric Cheng aip = NULL; 8968275SEric Cheng } 8978275SEric Cheng curr = buf + i + 1; 8988275SEric Cheng } 8998275SEric Cheng 9008275SEric Cheng *listp = list; 9018275SEric Cheng return (DLADM_STATUS_OK); 9028275SEric Cheng 9038275SEric Cheng fail: 9048275SEric Cheng dladm_free_args(list); 9058275SEric Cheng return (DLADM_STATUS_FAILED); 9068275SEric Cheng } 907