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 /* 225895Syz147064 * Copyright 2008 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> 32*8275SEric Cheng #include <stdlib.h> 336173Syz147064 #include <sys/param.h> 343147Sxc151355 #include <sys/stat.h> 353147Sxc151355 #include <libdladm_impl.h> 363184Smeem #include <libintl.h> 375895Syz147064 #include <libdlpi.h> 38733Skrgopi 393147Sxc151355 static char dladm_rootdir[MAXPATHLEN] = "/"; 403147Sxc151355 413147Sxc151355 const char * 423147Sxc151355 dladm_status2str(dladm_status_t status, char *buf) 433147Sxc151355 { 443147Sxc151355 const char *s; 453147Sxc151355 463147Sxc151355 switch (status) { 473147Sxc151355 case DLADM_STATUS_OK: 483147Sxc151355 s = "ok"; 493147Sxc151355 break; 503147Sxc151355 case DLADM_STATUS_BADARG: 513147Sxc151355 s = "invalid argument"; 523147Sxc151355 break; 533147Sxc151355 case DLADM_STATUS_FAILED: 543147Sxc151355 s = "operation failed"; 553147Sxc151355 break; 563147Sxc151355 case DLADM_STATUS_TOOSMALL: 573147Sxc151355 s = "buffer size too small"; 583147Sxc151355 break; 593147Sxc151355 case DLADM_STATUS_NOTSUP: 603147Sxc151355 s = "operation not supported"; 613147Sxc151355 break; 623147Sxc151355 case DLADM_STATUS_NOTFOUND: 633147Sxc151355 s = "object not found"; 643147Sxc151355 break; 653147Sxc151355 case DLADM_STATUS_BADVAL: 663147Sxc151355 s = "invalid value"; 673147Sxc151355 break; 683147Sxc151355 case DLADM_STATUS_NOMEM: 693147Sxc151355 s = "insufficient memory"; 703147Sxc151355 break; 713147Sxc151355 case DLADM_STATUS_EXIST: 723147Sxc151355 s = "object already exists"; 733147Sxc151355 break; 743147Sxc151355 case DLADM_STATUS_LINKINVAL: 753147Sxc151355 s = "invalid link"; 763147Sxc151355 break; 773147Sxc151355 case DLADM_STATUS_PROPRDONLY: 783147Sxc151355 s = "read-only property"; 793147Sxc151355 break; 803147Sxc151355 case DLADM_STATUS_BADVALCNT: 813147Sxc151355 s = "invalid number of values"; 823147Sxc151355 break; 833147Sxc151355 case DLADM_STATUS_DBNOTFOUND: 843147Sxc151355 s = "database not found"; 853147Sxc151355 break; 863147Sxc151355 case DLADM_STATUS_DENIED: 873147Sxc151355 s = "permission denied"; 883147Sxc151355 break; 893147Sxc151355 case DLADM_STATUS_IOERR: 903147Sxc151355 s = "I/O error"; 913147Sxc151355 break; 923448Sdh155122 case DLADM_STATUS_TEMPONLY: 93*8275SEric Cheng s = "change cannot be persistent"; 943448Sdh155122 break; 953871Syz147064 case DLADM_STATUS_TIMEDOUT: 963871Syz147064 s = "operation timed out"; 973871Syz147064 break; 983871Syz147064 case DLADM_STATUS_ISCONN: 993871Syz147064 s = "already connected"; 1003871Syz147064 break; 1013871Syz147064 case DLADM_STATUS_NOTCONN: 1023871Syz147064 s = "not connected"; 1033871Syz147064 break; 1043871Syz147064 case DLADM_STATUS_REPOSITORYINVAL: 1053871Syz147064 s = "invalid configuration repository"; 1063871Syz147064 break; 1073871Syz147064 case DLADM_STATUS_MACADDRINVAL: 1083871Syz147064 s = "invalid MAC address"; 1093871Syz147064 break; 1103871Syz147064 case DLADM_STATUS_KEYINVAL: 1113871Syz147064 s = "invalid key"; 1123871Syz147064 break; 1135084Sjohnlev case DLADM_STATUS_INVALIDMACADDRLEN: 1145084Sjohnlev s = "invalid MAC address length"; 1155084Sjohnlev break; 1165084Sjohnlev case DLADM_STATUS_INVALIDMACADDRTYPE: 1175084Sjohnlev s = "invalid MAC address type"; 1185084Sjohnlev break; 1195895Syz147064 case DLADM_STATUS_LINKBUSY: 1205895Syz147064 s = "link busy"; 1215895Syz147064 break; 1225895Syz147064 case DLADM_STATUS_VIDINVAL: 1235895Syz147064 s = "invalid VLAN identifier"; 1245084Sjohnlev break; 1255895Syz147064 case DLADM_STATUS_TRYAGAIN: 1265895Syz147064 s = "try again later"; 1275084Sjohnlev break; 1285895Syz147064 case DLADM_STATUS_NONOTIF: 1295895Syz147064 s = "link notification is not supported"; 1305084Sjohnlev break; 131*8275SEric Cheng case DLADM_STATUS_BADTIMEVAL: 132*8275SEric Cheng s = "invalid time range"; 133*8275SEric Cheng break; 134*8275SEric Cheng case DLADM_STATUS_INVALIDMACADDR: 135*8275SEric Cheng s = "invalid MAC address value"; 136*8275SEric Cheng break; 137*8275SEric Cheng case DLADM_STATUS_INVALIDMACADDRNIC: 138*8275SEric Cheng s = "MAC address reserved for use by underlying data-link"; 139*8275SEric Cheng break; 140*8275SEric Cheng case DLADM_STATUS_INVALIDMACADDRINUSE: 141*8275SEric Cheng s = "MAC address is already in use"; 142*8275SEric Cheng break; 143*8275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTINVALID: 144*8275SEric Cheng s = "invalid factory MAC address slot"; 145*8275SEric Cheng break; 146*8275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTUSED: 147*8275SEric Cheng s = "factory MAC address slot already used"; 148*8275SEric Cheng break; 149*8275SEric Cheng case DLADM_STATUS_MACFACTORYSLOTALLUSED: 150*8275SEric Cheng s = "all factory MAC address slots are in use"; 151*8275SEric Cheng break; 152*8275SEric Cheng case DLADM_STATUS_MACFACTORYNOTSUP: 153*8275SEric Cheng s = "factory MAC address slots not supported"; 154*8275SEric Cheng break; 155*8275SEric Cheng case DLADM_STATUS_INVALIDMACPREFIX: 156*8275SEric Cheng s = "Invalid MAC address prefix value"; 157*8275SEric Cheng break; 158*8275SEric Cheng case DLADM_STATUS_INVALIDMACPREFIXLEN: 159*8275SEric Cheng s = "Invalid MAC address prefix length"; 160*8275SEric Cheng break; 161*8275SEric Cheng case DLADM_STATUS_CPUMAX: 162*8275SEric Cheng s = "non-existent processor ID"; 163*8275SEric Cheng break; 164*8275SEric Cheng case DLADM_STATUS_CPUERR: 165*8275SEric Cheng s = "could not determine processor status"; 166*8275SEric Cheng break; 167*8275SEric Cheng case DLADM_STATUS_CPUNOTONLINE: 168*8275SEric Cheng s = "processor not online"; 169*8275SEric Cheng break; 170*8275SEric Cheng case DLADM_STATUS_DB_NOTFOUND: 171*8275SEric Cheng s = "database not found"; 172*8275SEric Cheng break; 173*8275SEric Cheng case DLADM_STATUS_DB_PARSE_ERR: 174*8275SEric Cheng s = "database parse error"; 175*8275SEric Cheng break; 176*8275SEric Cheng case DLADM_STATUS_PROP_PARSE_ERR: 177*8275SEric Cheng s = "property parse error"; 178*8275SEric Cheng break; 179*8275SEric Cheng case DLADM_STATUS_ATTR_PARSE_ERR: 180*8275SEric Cheng s = "attribute parse error"; 181*8275SEric Cheng break; 182*8275SEric Cheng case DLADM_STATUS_FLOW_DB_ERR: 183*8275SEric Cheng s = "flow database error"; 184*8275SEric Cheng break; 185*8275SEric Cheng case DLADM_STATUS_FLOW_DB_OPEN_ERR: 186*8275SEric Cheng s = "flow database open error"; 187*8275SEric Cheng break; 188*8275SEric Cheng case DLADM_STATUS_FLOW_DB_PARSE_ERR: 189*8275SEric Cheng s = "flow database parse error"; 190*8275SEric Cheng break; 191*8275SEric Cheng case DLADM_STATUS_FLOWPROP_DB_PARSE_ERR: 192*8275SEric Cheng s = "flow property database parse error"; 193*8275SEric Cheng break; 194*8275SEric Cheng case DLADM_STATUS_FLOW_ADD_ERR: 195*8275SEric Cheng s = "flow add error"; 196*8275SEric Cheng break; 197*8275SEric Cheng case DLADM_STATUS_FLOW_WALK_ERR: 198*8275SEric Cheng s = "flow walk error"; 199*8275SEric Cheng break; 200*8275SEric Cheng case DLADM_STATUS_FLOW_IDENTICAL: 201*8275SEric Cheng s = "a flow with identical attributes exists"; 202*8275SEric Cheng break; 203*8275SEric Cheng case DLADM_STATUS_FLOW_INCOMPATIBLE: 204*8275SEric Cheng s = "flow(s) with incompatible attributes exists"; 205*8275SEric Cheng break; 206*8275SEric Cheng case DLADM_STATUS_FLOW_EXISTS: 207*8275SEric Cheng s = "link still has flows"; 208*8275SEric Cheng break; 209*8275SEric Cheng case DLADM_STATUS_PERSIST_FLOW_EXISTS: 210*8275SEric Cheng s = "persistent flow with the same name exists"; 211*8275SEric Cheng break; 212*8275SEric Cheng case DLADM_STATUS_INVALID_IP: 213*8275SEric Cheng s = "invalid IP address"; 214*8275SEric Cheng break; 215*8275SEric Cheng case DLADM_STATUS_INVALID_PREFIXLEN: 216*8275SEric Cheng s = "invalid IP prefix length"; 217*8275SEric Cheng break; 218*8275SEric Cheng case DLADM_STATUS_INVALID_PROTOCOL: 219*8275SEric Cheng s = "invalid IP protocol"; 220*8275SEric Cheng break; 221*8275SEric Cheng case DLADM_STATUS_INVALID_PORT: 222*8275SEric Cheng s = "invalid port number"; 223*8275SEric Cheng break; 224*8275SEric Cheng case DLADM_STATUS_INVALID_DSF: 225*8275SEric Cheng s = "invalid dsfield"; 226*8275SEric Cheng break; 227*8275SEric Cheng case DLADM_STATUS_INVALID_DSFMASK: 228*8275SEric Cheng s = "invalid dsfield mask"; 229*8275SEric Cheng break; 230*8275SEric Cheng case DLADM_STATUS_INVALID_MACMARGIN: 231*8275SEric Cheng s = "MTU check failed, use lower MTU or -f option"; 232*8275SEric Cheng break; 233*8275SEric Cheng case DLADM_STATUS_BADPROP: 234*8275SEric Cheng s = "invalid property"; 235*8275SEric Cheng break; 236*8275SEric Cheng case DLADM_STATUS_MINMAXBW: 237*8275SEric Cheng s = "minimum value for maxbw is 1.2M"; 238*8275SEric Cheng break; 239*8275SEric Cheng case DLADM_STATUS_NO_HWRINGS: 240*8275SEric Cheng s = "request hw rings failed"; 241*8275SEric Cheng break; 2423147Sxc151355 default: 2433184Smeem s = "<unknown error>"; 2443184Smeem break; 2453147Sxc151355 } 2463184Smeem (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 2473147Sxc151355 return (buf); 2483147Sxc151355 } 2493147Sxc151355 2503147Sxc151355 /* 2513147Sxc151355 * Convert a unix errno to a dladm_status_t. 2523147Sxc151355 * We only convert errnos that are likely to be encountered. All others 2533147Sxc151355 * are mapped to DLADM_STATUS_FAILED. 2543147Sxc151355 */ 2553147Sxc151355 dladm_status_t 2563147Sxc151355 dladm_errno2status(int err) 2573147Sxc151355 { 2583147Sxc151355 switch (err) { 2595903Ssowmini case 0: 2605903Ssowmini return (DLADM_STATUS_OK); 2613147Sxc151355 case EINVAL: 2623147Sxc151355 return (DLADM_STATUS_BADARG); 2633147Sxc151355 case EEXIST: 2643147Sxc151355 return (DLADM_STATUS_EXIST); 2653147Sxc151355 case ENOENT: 2663147Sxc151355 return (DLADM_STATUS_NOTFOUND); 2673147Sxc151355 case ENOSPC: 2683147Sxc151355 return (DLADM_STATUS_TOOSMALL); 2693147Sxc151355 case ENOMEM: 2703147Sxc151355 return (DLADM_STATUS_NOMEM); 2713147Sxc151355 case ENOTSUP: 2723147Sxc151355 return (DLADM_STATUS_NOTSUP); 2735895Syz147064 case ENETDOWN: 2745895Syz147064 return (DLADM_STATUS_NONOTIF); 2753147Sxc151355 case EACCES: 2767408SSebastien.Roy@Sun.COM case EPERM: 2773147Sxc151355 return (DLADM_STATUS_DENIED); 2783147Sxc151355 case EIO: 2793147Sxc151355 return (DLADM_STATUS_IOERR); 2805084Sjohnlev case EBUSY: 2815895Syz147064 return (DLADM_STATUS_LINKBUSY); 2825895Syz147064 case EAGAIN: 2835895Syz147064 return (DLADM_STATUS_TRYAGAIN); 284*8275SEric Cheng case ENOTEMPTY: 285*8275SEric Cheng return (DLADM_STATUS_FLOW_EXISTS); 286*8275SEric Cheng case EOPNOTSUPP: 287*8275SEric Cheng return (DLADM_STATUS_FLOW_INCOMPATIBLE); 288*8275SEric Cheng case EALREADY: 289*8275SEric Cheng return (DLADM_STATUS_FLOW_IDENTICAL); 2903147Sxc151355 default: 2913147Sxc151355 return (DLADM_STATUS_FAILED); 2923147Sxc151355 } 2933147Sxc151355 } 2943147Sxc151355 295*8275SEric Cheng dladm_status_t 296*8275SEric Cheng dladm_str2bw(char *oarg, uint64_t *bw) 297*8275SEric Cheng { 298*8275SEric Cheng char *endp = NULL; 299*8275SEric Cheng int64_t n; 300*8275SEric Cheng int mult = 1; 301*8275SEric Cheng 302*8275SEric Cheng n = strtoull(oarg, &endp, 10); 303*8275SEric Cheng 304*8275SEric Cheng if ((errno != 0) || (strlen(endp) > 1)) 305*8275SEric Cheng return (DLADM_STATUS_BADARG); 306*8275SEric Cheng 307*8275SEric Cheng if (n < 0) 308*8275SEric Cheng return (DLADM_STATUS_BADVAL); 309*8275SEric Cheng 310*8275SEric Cheng switch (*endp) { 311*8275SEric Cheng case 'k': 312*8275SEric Cheng case 'K': 313*8275SEric Cheng mult = 1000; 314*8275SEric Cheng break; 315*8275SEric Cheng case 'm': 316*8275SEric Cheng case 'M': 317*8275SEric Cheng case '\0': 318*8275SEric Cheng mult = 1000000; 319*8275SEric Cheng break; 320*8275SEric Cheng case 'g': 321*8275SEric Cheng case 'G': 322*8275SEric Cheng mult = 1000000000; 323*8275SEric Cheng break; 324*8275SEric Cheng case '%': 325*8275SEric Cheng /* 326*8275SEric Cheng * percentages not supported for now, 327*8275SEric Cheng * see RFE 6540675 328*8275SEric Cheng */ 329*8275SEric Cheng return (DLADM_STATUS_NOTSUP); 330*8275SEric Cheng default: 331*8275SEric Cheng return (DLADM_STATUS_BADVAL); 332*8275SEric Cheng } 333*8275SEric Cheng 334*8275SEric Cheng *bw = n * mult; 335*8275SEric Cheng 336*8275SEric Cheng /* check for overflow */ 337*8275SEric Cheng if (*bw / mult != n) 338*8275SEric Cheng return (DLADM_STATUS_BADARG); 339*8275SEric Cheng 340*8275SEric Cheng return (DLADM_STATUS_OK); 341*8275SEric Cheng } 342*8275SEric Cheng 343*8275SEric Cheng /* 344*8275SEric Cheng * Convert bandwidth in bps to a string in mpbs. For values greater 345*8275SEric Cheng * than 1mbps or 1000000, print a whole mbps value. For values that 346*8275SEric Cheng * have fractional Mbps in whole Kbps , print the bandwidth in a manner 347*8275SEric Cheng * simlilar to a floating point format. 348*8275SEric Cheng * 349*8275SEric Cheng * bps string 350*8275SEric Cheng * 0 0 351*8275SEric Cheng * 100 0 352*8275SEric Cheng * 2000 0.002 353*8275SEric Cheng * 431000 0.431 354*8275SEric Cheng * 1000000 1 355*8275SEric Cheng * 1030000 1.030 356*8275SEric Cheng * 100000000 100 357*8275SEric Cheng */ 358*8275SEric Cheng const char * 359*8275SEric Cheng dladm_bw2str(int64_t bw, char *buf) 360*8275SEric Cheng { 361*8275SEric Cheng int kbps, mbps; 362*8275SEric Cheng 363*8275SEric Cheng kbps = (bw%1000000)/1000; 364*8275SEric Cheng mbps = bw/1000000; 365*8275SEric Cheng if (kbps != 0) { 366*8275SEric Cheng if (mbps == 0) 367*8275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 368*8275SEric Cheng else 369*8275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 370*8275SEric Cheng kbps); 371*8275SEric Cheng } else { 372*8275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 373*8275SEric Cheng } 374*8275SEric Cheng 375*8275SEric Cheng return (buf); 376*8275SEric Cheng } 377*8275SEric Cheng 3785895Syz147064 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 3793147Sxc151355 3803147Sxc151355 static int 3813147Sxc151355 i_dladm_lock_db(const char *lock_file, short type) 3823147Sxc151355 { 3833147Sxc151355 int lock_fd; 3845895Syz147064 struct flock lock; 3853147Sxc151355 3863147Sxc151355 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 3873147Sxc151355 LOCK_DB_PERMS)) < 0) 3883147Sxc151355 return (-1); 3893147Sxc151355 3903147Sxc151355 lock.l_type = type; 3913147Sxc151355 lock.l_whence = SEEK_SET; 3923147Sxc151355 lock.l_start = 0; 3933147Sxc151355 lock.l_len = 0; 3943147Sxc151355 3953147Sxc151355 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 3963147Sxc151355 int err = errno; 3973147Sxc151355 3983147Sxc151355 (void) close(lock_fd); 3993147Sxc151355 (void) unlink(lock_file); 4003147Sxc151355 errno = err; 4013147Sxc151355 return (-1); 4023147Sxc151355 } 4033147Sxc151355 return (lock_fd); 4043147Sxc151355 } 4053147Sxc151355 4063147Sxc151355 static void 4073147Sxc151355 i_dladm_unlock_db(const char *lock_file, int fd) 4083147Sxc151355 { 4093147Sxc151355 struct flock lock; 4103147Sxc151355 4113147Sxc151355 if (fd < 0) 4123147Sxc151355 return; 4133147Sxc151355 4143147Sxc151355 lock.l_type = F_UNLCK; 4153147Sxc151355 lock.l_whence = SEEK_SET; 4163147Sxc151355 lock.l_start = 0; 4173147Sxc151355 lock.l_len = 0; 4183147Sxc151355 4193147Sxc151355 (void) fcntl(fd, F_SETLKW, &lock); 4203147Sxc151355 (void) close(fd); 4213147Sxc151355 (void) unlink(lock_file); 4223147Sxc151355 } 4233147Sxc151355 4245895Syz147064 /* 4255895Syz147064 * Given a link class, returns its class string. 4265895Syz147064 */ 4275895Syz147064 const char * 4285895Syz147064 dladm_class2str(datalink_class_t class, char *buf) 4295895Syz147064 { 4305895Syz147064 const char *s; 4315895Syz147064 4325895Syz147064 switch (class) { 4335895Syz147064 case DATALINK_CLASS_PHYS: 4345895Syz147064 s = "phys"; 4355895Syz147064 break; 4365895Syz147064 case DATALINK_CLASS_VLAN: 4375895Syz147064 s = "vlan"; 4385895Syz147064 break; 4395895Syz147064 case DATALINK_CLASS_AGGR: 4405895Syz147064 s = "aggr"; 4415895Syz147064 break; 4425895Syz147064 case DATALINK_CLASS_VNIC: 4435895Syz147064 s = "vnic"; 4445895Syz147064 break; 445*8275SEric Cheng case DATALINK_CLASS_ETHERSTUB: 446*8275SEric Cheng s = "etherstub"; 447*8275SEric Cheng break; 4485895Syz147064 default: 4495895Syz147064 s = "unknown"; 4505895Syz147064 break; 4515895Syz147064 } 4525895Syz147064 4535895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 4545895Syz147064 return (buf); 4555895Syz147064 } 4565895Syz147064 4575895Syz147064 /* 4585895Syz147064 * Given a physical link media type, returns its media type string. 4595895Syz147064 */ 4605895Syz147064 const char * 4615895Syz147064 dladm_media2str(uint32_t media, char *buf) 4625895Syz147064 { 4635895Syz147064 const char *s; 4645895Syz147064 4655895Syz147064 switch (media) { 4665895Syz147064 case DL_ETHER: 4675895Syz147064 s = "Ethernet"; 4685895Syz147064 break; 4695895Syz147064 case DL_WIFI: 4705895Syz147064 s = "WiFi"; 4715895Syz147064 break; 4725895Syz147064 case DL_IB: 4735895Syz147064 s = "Infiniband"; 4745895Syz147064 break; 4755895Syz147064 case DL_IPV4: 4765895Syz147064 s = "IPv4Tunnel"; 4775895Syz147064 break; 4785895Syz147064 case DL_IPV6: 4795895Syz147064 s = "IPv6Tunnel"; 4805895Syz147064 break; 4815895Syz147064 case DL_CSMACD: 4825895Syz147064 s = "CSMA/CD"; 4835895Syz147064 break; 4845895Syz147064 case DL_TPB: 4855895Syz147064 s = "TokenBus"; 4865895Syz147064 break; 4875895Syz147064 case DL_TPR: 4885895Syz147064 s = "TokenRing"; 4895895Syz147064 break; 4905895Syz147064 case DL_METRO: 4915895Syz147064 s = "MetroNet"; 4925895Syz147064 break; 4935895Syz147064 case DL_HDLC: 4945895Syz147064 s = "HDLC"; 4955895Syz147064 break; 4965895Syz147064 case DL_CHAR: 4975895Syz147064 s = "SyncCharacter"; 4985895Syz147064 break; 4995895Syz147064 case DL_CTCA: 5005895Syz147064 s = "CTCA"; 5015895Syz147064 break; 5025895Syz147064 case DL_FDDI: 5035895Syz147064 s = "FDDI"; 5045895Syz147064 break; 5055895Syz147064 case DL_FC: 5065895Syz147064 s = "FiberChannel"; 5075895Syz147064 break; 5085895Syz147064 case DL_ATM: 5095895Syz147064 s = "ATM"; 5105895Syz147064 break; 5115895Syz147064 case DL_IPATM: 5125895Syz147064 s = "ATM(ClassicIP)"; 5135895Syz147064 break; 5145895Syz147064 case DL_X25: 5155895Syz147064 s = "X.25"; 5165895Syz147064 break; 5175895Syz147064 case DL_IPX25: 5185895Syz147064 s = "X.25(ClassicIP)"; 5195895Syz147064 break; 5205895Syz147064 case DL_ISDN: 5215895Syz147064 s = "ISDN"; 5225895Syz147064 break; 5235895Syz147064 case DL_HIPPI: 5245895Syz147064 s = "HIPPI"; 5255895Syz147064 break; 5265895Syz147064 case DL_100VG: 5275895Syz147064 s = "100BaseVGEthernet"; 5285895Syz147064 break; 5295895Syz147064 case DL_100VGTPR: 5305895Syz147064 s = "100BaseVGTokenRing"; 5315895Syz147064 break; 5325895Syz147064 case DL_ETH_CSMA: 5335895Syz147064 s = "IEEE802.3"; 5345895Syz147064 break; 5355895Syz147064 case DL_100BT: 5365895Syz147064 s = "100BaseT"; 5375895Syz147064 break; 5385895Syz147064 case DL_FRAME: 5395895Syz147064 s = "FrameRelay"; 5405895Syz147064 break; 5415895Syz147064 case DL_MPFRAME: 5425895Syz147064 s = "MPFrameRelay"; 5435895Syz147064 break; 5445895Syz147064 case DL_ASYNC: 5455895Syz147064 s = "AsyncCharacter"; 5465895Syz147064 break; 5478023SPhil.Kirk@Sun.COM case DL_IPNET: 5488023SPhil.Kirk@Sun.COM s = "IPNET"; 5498023SPhil.Kirk@Sun.COM break; 5505895Syz147064 default: 5515895Syz147064 s = "--"; 5525895Syz147064 break; 5535895Syz147064 } 5545895Syz147064 5555895Syz147064 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 5565895Syz147064 return (buf); 5575895Syz147064 } 5585895Syz147064 5593147Sxc151355 dladm_status_t 5603147Sxc151355 i_dladm_rw_db(const char *db_file, mode_t db_perms, 5613147Sxc151355 dladm_status_t (*process_db)(void *, FILE *, FILE *), 5623147Sxc151355 void *arg, boolean_t writeop) 5633147Sxc151355 { 5643147Sxc151355 dladm_status_t status = DLADM_STATUS_OK; 5653147Sxc151355 FILE *fp, *nfp = NULL; 5663147Sxc151355 char lock[MAXPATHLEN]; 5673147Sxc151355 char file[MAXPATHLEN]; 5683147Sxc151355 char newfile[MAXPATHLEN]; 5693147Sxc151355 char *db_basename; 5703147Sxc151355 int nfd, lock_fd; 5713147Sxc151355 5723147Sxc151355 /* 5733147Sxc151355 * If we are called from a boot script such as net-physical, 5743147Sxc151355 * it's quite likely that the root fs is still not writable. 5753147Sxc151355 * For this case, it's ok for the lock creation to fail since 5763147Sxc151355 * no one else could be accessing our configuration file. 5773147Sxc151355 */ 5783147Sxc151355 db_basename = strrchr(db_file, '/'); 5793147Sxc151355 if (db_basename == NULL || db_basename[1] == '\0') 5803147Sxc151355 return (dladm_errno2status(EINVAL)); 5813147Sxc151355 db_basename++; 5823147Sxc151355 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 5833147Sxc151355 if ((lock_fd = i_dladm_lock_db 5843147Sxc151355 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 5853147Sxc151355 return (dladm_errno2status(errno)); 5863147Sxc151355 5873147Sxc151355 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 5883147Sxc151355 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 5893147Sxc151355 int err = errno; 5903147Sxc151355 5913147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 5923147Sxc151355 if (err == ENOENT) 5933147Sxc151355 return (DLADM_STATUS_DBNOTFOUND); 5943147Sxc151355 5953147Sxc151355 return (dladm_errno2status(err)); 5963147Sxc151355 } 5973147Sxc151355 5983147Sxc151355 if (writeop) { 5993147Sxc151355 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 6003147Sxc151355 dladm_rootdir, db_file); 6013147Sxc151355 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 6023147Sxc151355 db_perms)) < 0) { 6033147Sxc151355 (void) fclose(fp); 6043147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6053147Sxc151355 return (dladm_errno2status(errno)); 6063147Sxc151355 } 6073147Sxc151355 6083147Sxc151355 if ((nfp = fdopen(nfd, "w")) == NULL) { 6093147Sxc151355 (void) close(nfd); 6103147Sxc151355 (void) fclose(fp); 6113147Sxc151355 (void) unlink(newfile); 6123147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6133147Sxc151355 return (dladm_errno2status(errno)); 6143147Sxc151355 } 6153147Sxc151355 } 6163147Sxc151355 status = (*process_db)(arg, fp, nfp); 6173147Sxc151355 if (!writeop || status != DLADM_STATUS_OK) 6183147Sxc151355 goto done; 6193147Sxc151355 6203147Sxc151355 /* 6213147Sxc151355 * Configuration files need to be owned by the 'dladm' user. 6223147Sxc151355 * If we are invoked by root, the file ownership needs to be fixed. 6233147Sxc151355 */ 6243147Sxc151355 if (getuid() == 0 || geteuid() == 0) { 6256173Syz147064 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 6263147Sxc151355 status = dladm_errno2status(errno); 6273147Sxc151355 goto done; 6283147Sxc151355 } 6293147Sxc151355 } 6303147Sxc151355 6313147Sxc151355 if (fflush(nfp) == EOF) { 6323147Sxc151355 status = dladm_errno2status(errno); 6333147Sxc151355 goto done; 6343147Sxc151355 } 6353147Sxc151355 (void) fclose(fp); 6363147Sxc151355 (void) fclose(nfp); 6373147Sxc151355 6383147Sxc151355 if (rename(newfile, file) < 0) { 6393147Sxc151355 (void) unlink(newfile); 6403147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6413147Sxc151355 return (dladm_errno2status(errno)); 6423147Sxc151355 } 6433147Sxc151355 6443147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6453147Sxc151355 return (DLADM_STATUS_OK); 6463147Sxc151355 6473147Sxc151355 done: 6483147Sxc151355 if (nfp != NULL) { 6493147Sxc151355 (void) fclose(nfp); 6503147Sxc151355 if (status != DLADM_STATUS_OK) 6513147Sxc151355 (void) unlink(newfile); 6523147Sxc151355 } 6533147Sxc151355 (void) fclose(fp); 6543147Sxc151355 i_dladm_unlock_db(lock, lock_fd); 6553147Sxc151355 return (status); 6563147Sxc151355 } 6573147Sxc151355 6583147Sxc151355 dladm_status_t 6593147Sxc151355 dladm_set_rootdir(const char *rootdir) 6603147Sxc151355 { 6613147Sxc151355 DIR *dp; 6623147Sxc151355 6633147Sxc151355 if (rootdir == NULL || *rootdir != '/' || 6643147Sxc151355 (dp = opendir(rootdir)) == NULL) 6653147Sxc151355 return (DLADM_STATUS_BADARG); 6663147Sxc151355 6673147Sxc151355 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 6683147Sxc151355 (void) closedir(dp); 6693147Sxc151355 return (DLADM_STATUS_OK); 6703147Sxc151355 } 6715895Syz147064 6725895Syz147064 boolean_t 6735895Syz147064 dladm_valid_linkname(const char *link) 6745895Syz147064 { 6755895Syz147064 size_t len = strlen(link); 6765895Syz147064 const char *cp; 6775895Syz147064 6785895Syz147064 if (len + 1 >= MAXLINKNAMELEN) 6795895Syz147064 return (B_FALSE); 6805895Syz147064 6815895Syz147064 /* 6825895Syz147064 * The link name cannot start with a digit and must end with a digit. 6835895Syz147064 */ 6845895Syz147064 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 6855895Syz147064 return (B_FALSE); 6865895Syz147064 6875895Syz147064 /* 6885895Syz147064 * The legal characters in a link name are: 6895895Syz147064 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 6905895Syz147064 */ 6915895Syz147064 for (cp = link; *cp != '\0'; cp++) { 6925895Syz147064 if ((isalnum(*cp) == 0) && (*cp != '_')) 6935895Syz147064 return (B_FALSE); 6945895Syz147064 } 6955895Syz147064 6965895Syz147064 return (B_TRUE); 6975895Syz147064 } 698*8275SEric Cheng 699*8275SEric Cheng /* 700*8275SEric Cheng * Convert priority string to a value. 701*8275SEric Cheng */ 702*8275SEric Cheng dladm_status_t 703*8275SEric Cheng dladm_str2pri(char *token, mac_priority_level_t *pri) 704*8275SEric Cheng { 705*8275SEric Cheng if (strlen(token) == strlen("low") && 706*8275SEric Cheng strncasecmp(token, "low", strlen("low")) == 0) { 707*8275SEric Cheng *pri = MPL_LOW; 708*8275SEric Cheng } else if (strlen(token) == strlen("medium") && 709*8275SEric Cheng strncasecmp(token, "medium", strlen("medium")) == 0) { 710*8275SEric Cheng *pri = MPL_MEDIUM; 711*8275SEric Cheng } else if (strlen(token) == strlen("high") && 712*8275SEric Cheng strncasecmp(token, "high", strlen("high")) == 0) { 713*8275SEric Cheng *pri = MPL_HIGH; 714*8275SEric Cheng } else { 715*8275SEric Cheng return (DLADM_STATUS_BADVAL); 716*8275SEric Cheng } 717*8275SEric Cheng return (DLADM_STATUS_OK); 718*8275SEric Cheng } 719*8275SEric Cheng 720*8275SEric Cheng /* 721*8275SEric Cheng * Convert priority value to a string. 722*8275SEric Cheng */ 723*8275SEric Cheng const char * 724*8275SEric Cheng dladm_pri2str(mac_priority_level_t pri, char *buf) 725*8275SEric Cheng { 726*8275SEric Cheng const char *s; 727*8275SEric Cheng 728*8275SEric Cheng switch (pri) { 729*8275SEric Cheng case MPL_LOW: 730*8275SEric Cheng s = "low"; 731*8275SEric Cheng break; 732*8275SEric Cheng case MPL_MEDIUM: 733*8275SEric Cheng s = "medium"; 734*8275SEric Cheng break; 735*8275SEric Cheng case MPL_HIGH: 736*8275SEric Cheng s = "high"; 737*8275SEric Cheng break; 738*8275SEric Cheng default: 739*8275SEric Cheng s = "--"; 740*8275SEric Cheng break; 741*8275SEric Cheng } 742*8275SEric Cheng (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 743*8275SEric Cheng return (buf); 744*8275SEric Cheng } 745*8275SEric Cheng 746*8275SEric Cheng void 747*8275SEric Cheng dladm_free_args(dladm_arg_list_t *list) 748*8275SEric Cheng { 749*8275SEric Cheng if (list != NULL) { 750*8275SEric Cheng free(list->al_buf); 751*8275SEric Cheng free(list); 752*8275SEric Cheng } 753*8275SEric Cheng } 754*8275SEric Cheng 755*8275SEric Cheng dladm_status_t 756*8275SEric Cheng dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 757*8275SEric Cheng { 758*8275SEric Cheng dladm_arg_list_t *list; 759*8275SEric Cheng dladm_arg_info_t *aip; 760*8275SEric Cheng char *buf, *curr; 761*8275SEric Cheng int len, i; 762*8275SEric Cheng 763*8275SEric Cheng list = malloc(sizeof (dladm_arg_list_t)); 764*8275SEric Cheng if (list == NULL) 765*8275SEric Cheng return (dladm_errno2status(errno)); 766*8275SEric Cheng 767*8275SEric Cheng list->al_count = 0; 768*8275SEric Cheng list->al_buf = buf = strdup(str); 769*8275SEric Cheng if (buf == NULL) 770*8275SEric Cheng return (dladm_errno2status(errno)); 771*8275SEric Cheng 772*8275SEric Cheng curr = buf; 773*8275SEric Cheng len = strlen(buf); 774*8275SEric Cheng aip = NULL; 775*8275SEric Cheng for (i = 0; i < len; i++) { 776*8275SEric Cheng char c = buf[i]; 777*8275SEric Cheng boolean_t match = (c == '=' || c == ','); 778*8275SEric Cheng 779*8275SEric Cheng if (!match && i != len - 1) 780*8275SEric Cheng continue; 781*8275SEric Cheng 782*8275SEric Cheng if (match) { 783*8275SEric Cheng buf[i] = '\0'; 784*8275SEric Cheng if (*curr == '\0') 785*8275SEric Cheng goto fail; 786*8275SEric Cheng } 787*8275SEric Cheng 788*8275SEric Cheng if (aip != NULL && c != '=') { 789*8275SEric Cheng if (aip->ai_count > DLADM_MAX_ARG_VALS) 790*8275SEric Cheng goto fail; 791*8275SEric Cheng 792*8275SEric Cheng if (novalues) 793*8275SEric Cheng goto fail; 794*8275SEric Cheng 795*8275SEric Cheng aip->ai_val[aip->ai_count] = curr; 796*8275SEric Cheng aip->ai_count++; 797*8275SEric Cheng } else { 798*8275SEric Cheng if (list->al_count > DLADM_MAX_ARG_VALS) 799*8275SEric Cheng goto fail; 800*8275SEric Cheng 801*8275SEric Cheng aip = &list->al_info[list->al_count]; 802*8275SEric Cheng aip->ai_name = curr; 803*8275SEric Cheng aip->ai_count = 0; 804*8275SEric Cheng list->al_count++; 805*8275SEric Cheng if (c == ',') 806*8275SEric Cheng aip = NULL; 807*8275SEric Cheng } 808*8275SEric Cheng curr = buf + i + 1; 809*8275SEric Cheng } 810*8275SEric Cheng 811*8275SEric Cheng *listp = list; 812*8275SEric Cheng return (DLADM_STATUS_OK); 813*8275SEric Cheng 814*8275SEric Cheng fail: 815*8275SEric Cheng dladm_free_args(list); 816*8275SEric Cheng return (DLADM_STATUS_FAILED); 817*8275SEric Cheng } 818