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