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