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