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