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 2009 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 boolean_t 362 dladm_str2interval(char *oarg, uint32_t *interval) 363 { 364 int val; 365 char *endp = NULL; 366 367 errno = 0; 368 val = strtol(oarg, &endp, 10); 369 if (errno != 0 || val <= 0 || *endp != '\0') 370 return (B_FALSE); 371 372 *interval = val; 373 374 return (B_TRUE); 375 } 376 377 dladm_status_t 378 dladm_str2bw(char *oarg, uint64_t *bw) 379 { 380 char *endp = NULL; 381 int64_t n; 382 int mult = 1; 383 384 n = strtoull(oarg, &endp, 10); 385 386 if ((errno != 0) || (strlen(endp) > 1)) 387 return (DLADM_STATUS_BADARG); 388 389 if (n < 0) 390 return (DLADM_STATUS_BADVAL); 391 392 switch (*endp) { 393 case 'k': 394 case 'K': 395 mult = 1000; 396 break; 397 case 'm': 398 case 'M': 399 case '\0': 400 mult = 1000000; 401 break; 402 case 'g': 403 case 'G': 404 mult = 1000000000; 405 break; 406 case '%': 407 /* 408 * percentages not supported for now, 409 * see RFE 6540675 410 */ 411 return (DLADM_STATUS_NOTSUP); 412 default: 413 return (DLADM_STATUS_BADVAL); 414 } 415 416 *bw = n * mult; 417 418 /* check for overflow */ 419 if (*bw / mult != n) 420 return (DLADM_STATUS_BADARG); 421 422 return (DLADM_STATUS_OK); 423 } 424 425 /* 426 * Convert bandwidth in bps to a string in mpbs. For values greater 427 * than 1mbps or 1000000, print a whole mbps value. For values that 428 * have fractional Mbps in whole Kbps , print the bandwidth in a manner 429 * simlilar to a floating point format. 430 * 431 * bps string 432 * 0 0 433 * 100 0 434 * 2000 0.002 435 * 431000 0.431 436 * 1000000 1 437 * 1030000 1.030 438 * 100000000 100 439 */ 440 const char * 441 dladm_bw2str(int64_t bw, char *buf) 442 { 443 int kbps, mbps; 444 445 kbps = (bw%1000000)/1000; 446 mbps = bw/1000000; 447 if (kbps != 0) { 448 if (mbps == 0) 449 (void) snprintf(buf, DLADM_STRSIZE, "0.%03u", kbps); 450 else 451 (void) snprintf(buf, DLADM_STRSIZE, "%5u.%03u", mbps, 452 kbps); 453 } else { 454 (void) snprintf(buf, DLADM_STRSIZE, "%5u", mbps); 455 } 456 457 return (buf); 458 } 459 460 #define LOCK_DB_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH 461 462 static int 463 i_dladm_lock_db(const char *lock_file, short type) 464 { 465 int lock_fd; 466 struct flock lock; 467 468 if ((lock_fd = open(lock_file, O_RDWR | O_CREAT | O_TRUNC, 469 LOCK_DB_PERMS)) < 0) 470 return (-1); 471 472 lock.l_type = type; 473 lock.l_whence = SEEK_SET; 474 lock.l_start = 0; 475 lock.l_len = 0; 476 477 if (fcntl(lock_fd, F_SETLKW, &lock) < 0) { 478 int err = errno; 479 480 (void) close(lock_fd); 481 (void) unlink(lock_file); 482 errno = err; 483 return (-1); 484 } 485 return (lock_fd); 486 } 487 488 static void 489 i_dladm_unlock_db(const char *lock_file, int fd) 490 { 491 struct flock lock; 492 493 if (fd < 0) 494 return; 495 496 lock.l_type = F_UNLCK; 497 lock.l_whence = SEEK_SET; 498 lock.l_start = 0; 499 lock.l_len = 0; 500 501 (void) fcntl(fd, F_SETLKW, &lock); 502 (void) close(fd); 503 (void) unlink(lock_file); 504 } 505 506 /* 507 * Given a link class, returns its class string. 508 */ 509 const char * 510 dladm_class2str(datalink_class_t class, char *buf) 511 { 512 const char *s; 513 514 switch (class) { 515 case DATALINK_CLASS_PHYS: 516 s = "phys"; 517 break; 518 case DATALINK_CLASS_VLAN: 519 s = "vlan"; 520 break; 521 case DATALINK_CLASS_AGGR: 522 s = "aggr"; 523 break; 524 case DATALINK_CLASS_VNIC: 525 s = "vnic"; 526 break; 527 case DATALINK_CLASS_ETHERSTUB: 528 s = "etherstub"; 529 break; 530 default: 531 s = "unknown"; 532 break; 533 } 534 535 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 536 return (buf); 537 } 538 539 /* 540 * Given a physical link media type, returns its media type string. 541 */ 542 const char * 543 dladm_media2str(uint32_t media, char *buf) 544 { 545 const char *s; 546 547 switch (media) { 548 case DL_ETHER: 549 s = "Ethernet"; 550 break; 551 case DL_WIFI: 552 s = "WiFi"; 553 break; 554 case DL_IB: 555 s = "Infiniband"; 556 break; 557 case DL_IPV4: 558 s = "IPv4Tunnel"; 559 break; 560 case DL_IPV6: 561 s = "IPv6Tunnel"; 562 break; 563 case DL_CSMACD: 564 s = "CSMA/CD"; 565 break; 566 case DL_TPB: 567 s = "TokenBus"; 568 break; 569 case DL_TPR: 570 s = "TokenRing"; 571 break; 572 case DL_METRO: 573 s = "MetroNet"; 574 break; 575 case DL_HDLC: 576 s = "HDLC"; 577 break; 578 case DL_CHAR: 579 s = "SyncCharacter"; 580 break; 581 case DL_CTCA: 582 s = "CTCA"; 583 break; 584 case DL_FDDI: 585 s = "FDDI"; 586 break; 587 case DL_FC: 588 s = "FiberChannel"; 589 break; 590 case DL_ATM: 591 s = "ATM"; 592 break; 593 case DL_IPATM: 594 s = "ATM(ClassicIP)"; 595 break; 596 case DL_X25: 597 s = "X.25"; 598 break; 599 case DL_IPX25: 600 s = "X.25(ClassicIP)"; 601 break; 602 case DL_ISDN: 603 s = "ISDN"; 604 break; 605 case DL_HIPPI: 606 s = "HIPPI"; 607 break; 608 case DL_100VG: 609 s = "100BaseVGEthernet"; 610 break; 611 case DL_100VGTPR: 612 s = "100BaseVGTokenRing"; 613 break; 614 case DL_ETH_CSMA: 615 s = "IEEE802.3"; 616 break; 617 case DL_100BT: 618 s = "100BaseT"; 619 break; 620 case DL_FRAME: 621 s = "FrameRelay"; 622 break; 623 case DL_MPFRAME: 624 s = "MPFrameRelay"; 625 break; 626 case DL_ASYNC: 627 s = "AsyncCharacter"; 628 break; 629 case DL_IPNET: 630 s = "IPNET"; 631 break; 632 default: 633 s = "--"; 634 break; 635 } 636 637 (void) snprintf(buf, DLADM_STRSIZE, "%s", s); 638 return (buf); 639 } 640 641 dladm_status_t 642 i_dladm_rw_db(dladm_handle_t handle, const char *db_file, mode_t db_perms, 643 dladm_status_t (*process_db)(dladm_handle_t, void *, FILE *, FILE *), 644 void *arg, boolean_t writeop) 645 { 646 dladm_status_t status = DLADM_STATUS_OK; 647 FILE *fp, *nfp = NULL; 648 char lock[MAXPATHLEN]; 649 char file[MAXPATHLEN]; 650 char newfile[MAXPATHLEN]; 651 char *db_basename; 652 int nfd, lock_fd; 653 654 /* 655 * If we are called from a boot script such as net-physical, 656 * it's quite likely that the root fs is still not writable. 657 * For this case, it's ok for the lock creation to fail since 658 * no one else could be accessing our configuration file. 659 */ 660 db_basename = strrchr(db_file, '/'); 661 if (db_basename == NULL || db_basename[1] == '\0') 662 return (dladm_errno2status(EINVAL)); 663 db_basename++; 664 (void) snprintf(lock, MAXPATHLEN, "/tmp/%s.lock", db_basename); 665 if ((lock_fd = i_dladm_lock_db 666 (lock, (writeop ? F_WRLCK : F_RDLCK))) < 0 && errno != EROFS) 667 return (dladm_errno2status(errno)); 668 669 (void) snprintf(file, MAXPATHLEN, "%s/%s", dladm_rootdir, db_file); 670 if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) { 671 int err = errno; 672 673 i_dladm_unlock_db(lock, lock_fd); 674 if (err == ENOENT) 675 return (DLADM_STATUS_DBNOTFOUND); 676 677 return (dladm_errno2status(err)); 678 } 679 680 if (writeop) { 681 (void) snprintf(newfile, MAXPATHLEN, "%s/%s.new", 682 dladm_rootdir, db_file); 683 if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, 684 db_perms)) < 0) { 685 (void) fclose(fp); 686 i_dladm_unlock_db(lock, lock_fd); 687 return (dladm_errno2status(errno)); 688 } 689 690 if ((nfp = fdopen(nfd, "w")) == NULL) { 691 (void) close(nfd); 692 (void) fclose(fp); 693 (void) unlink(newfile); 694 i_dladm_unlock_db(lock, lock_fd); 695 return (dladm_errno2status(errno)); 696 } 697 } 698 status = (*process_db)(handle, arg, fp, nfp); 699 if (!writeop || status != DLADM_STATUS_OK) 700 goto done; 701 702 /* 703 * Configuration files need to be owned by the 'dladm' user. 704 * If we are invoked by root, the file ownership needs to be fixed. 705 */ 706 if (getuid() == 0 || geteuid() == 0) { 707 if (fchown(nfd, UID_DLADM, GID_SYS) < 0) { 708 status = dladm_errno2status(errno); 709 goto done; 710 } 711 } 712 713 if (fflush(nfp) == EOF) { 714 status = dladm_errno2status(errno); 715 goto done; 716 } 717 (void) fclose(fp); 718 (void) fclose(nfp); 719 720 if (rename(newfile, file) < 0) { 721 (void) unlink(newfile); 722 i_dladm_unlock_db(lock, lock_fd); 723 return (dladm_errno2status(errno)); 724 } 725 726 i_dladm_unlock_db(lock, lock_fd); 727 return (DLADM_STATUS_OK); 728 729 done: 730 if (nfp != NULL) { 731 (void) fclose(nfp); 732 if (status != DLADM_STATUS_OK) 733 (void) unlink(newfile); 734 } 735 (void) fclose(fp); 736 i_dladm_unlock_db(lock, lock_fd); 737 return (status); 738 } 739 740 dladm_status_t 741 dladm_set_rootdir(const char *rootdir) 742 { 743 DIR *dp; 744 745 if (rootdir == NULL || *rootdir != '/' || 746 (dp = opendir(rootdir)) == NULL) 747 return (DLADM_STATUS_BADARG); 748 749 (void) strncpy(dladm_rootdir, rootdir, MAXPATHLEN); 750 (void) closedir(dp); 751 return (DLADM_STATUS_OK); 752 } 753 754 boolean_t 755 dladm_valid_linkname(const char *link) 756 { 757 size_t len = strlen(link); 758 const char *cp; 759 760 if (len + 1 >= MAXLINKNAMELEN) 761 return (B_FALSE); 762 763 /* 764 * The link name cannot start with a digit and must end with a digit. 765 */ 766 if ((isdigit(link[0]) != 0) || (isdigit(link[len - 1]) == 0)) 767 return (B_FALSE); 768 769 /* 770 * The legal characters in a link name are: 771 * alphanumeric (a-z, A-Z, 0-9), and the underscore ('_'). 772 */ 773 for (cp = link; *cp != '\0'; cp++) { 774 if ((isalnum(*cp) == 0) && (*cp != '_')) 775 return (B_FALSE); 776 } 777 778 return (B_TRUE); 779 } 780 781 /* 782 * Convert priority string to a value. 783 */ 784 dladm_status_t 785 dladm_str2pri(char *token, mac_priority_level_t *pri) 786 { 787 if (strlen(token) == strlen("low") && 788 strncasecmp(token, "low", strlen("low")) == 0) { 789 *pri = MPL_LOW; 790 } else if (strlen(token) == strlen("medium") && 791 strncasecmp(token, "medium", strlen("medium")) == 0) { 792 *pri = MPL_MEDIUM; 793 } else if (strlen(token) == strlen("high") && 794 strncasecmp(token, "high", strlen("high")) == 0) { 795 *pri = MPL_HIGH; 796 } else { 797 return (DLADM_STATUS_BADVAL); 798 } 799 return (DLADM_STATUS_OK); 800 } 801 802 /* 803 * Convert priority value to a string. 804 */ 805 const char * 806 dladm_pri2str(mac_priority_level_t pri, char *buf) 807 { 808 const char *s; 809 810 switch (pri) { 811 case MPL_LOW: 812 s = "low"; 813 break; 814 case MPL_MEDIUM: 815 s = "medium"; 816 break; 817 case MPL_HIGH: 818 s = "high"; 819 break; 820 default: 821 s = "--"; 822 break; 823 } 824 (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s)); 825 return (buf); 826 } 827 828 void 829 dladm_free_args(dladm_arg_list_t *list) 830 { 831 if (list != NULL) { 832 free(list->al_buf); 833 free(list); 834 } 835 } 836 837 dladm_status_t 838 dladm_parse_args(char *str, dladm_arg_list_t **listp, boolean_t novalues) 839 { 840 dladm_arg_list_t *list; 841 dladm_arg_info_t *aip; 842 char *buf, *curr; 843 int len, i; 844 845 if (str == NULL) 846 return (DLADM_STATUS_BADVAL); 847 848 if (str[0] == '\0') 849 return (DLADM_STATUS_OK); 850 851 list = malloc(sizeof (dladm_arg_list_t)); 852 if (list == NULL) 853 return (dladm_errno2status(errno)); 854 855 list->al_count = 0; 856 list->al_buf = buf = strdup(str); 857 if (buf == NULL) 858 return (dladm_errno2status(errno)); 859 860 curr = buf; 861 len = strlen(buf); 862 aip = NULL; 863 for (i = 0; i < len; i++) { 864 char c = buf[i]; 865 boolean_t match = (c == '=' || c == ','); 866 867 if (!match && i != len - 1) 868 continue; 869 870 if (match) { 871 buf[i] = '\0'; 872 if (*curr == '\0') 873 goto fail; 874 } 875 876 if (aip != NULL && c != '=') { 877 if (aip->ai_count > DLADM_MAX_ARG_VALS) 878 goto fail; 879 880 if (novalues) 881 goto fail; 882 883 aip->ai_val[aip->ai_count] = curr; 884 aip->ai_count++; 885 } else { 886 if (list->al_count > DLADM_MAX_ARG_VALS) 887 goto fail; 888 889 aip = &list->al_info[list->al_count]; 890 aip->ai_name = curr; 891 aip->ai_count = 0; 892 list->al_count++; 893 if (c == ',') 894 aip = NULL; 895 } 896 curr = buf + i + 1; 897 } 898 899 *listp = list; 900 return (DLADM_STATUS_OK); 901 902 fail: 903 dladm_free_args(list); 904 return (DLADM_STATUS_FAILED); 905 } 906