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