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