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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <unistd.h> 31 #include <stropts.h> 32 #include <sys/sockio.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <sys/socket.h> 36 #include <net/route.h> 37 #include <netinet/in.h> 38 #include <inet/ip.h> 39 #include <arpa/inet.h> 40 #include <libintl.h> 41 #include <libdlpi.h> 42 #include <libinetutil.h> 43 #include <libdladm.h> 44 #include <libdllink.h> 45 #include <libdliptun.h> 46 #include <strings.h> 47 #include <zone.h> 48 #include <ctype.h> 49 #include <limits.h> 50 #include <assert.h> 51 #include <netdb.h> 52 #include <pwd.h> 53 #include <auth_attr.h> 54 #include <secdb.h> 55 #include <nss_dbdefs.h> 56 #include "libipadm_impl.h" 57 58 /* error codes and text description */ 59 static struct ipadm_error_info { 60 ipadm_status_t error_code; 61 const char *error_desc; 62 } ipadm_errors[] = { 63 { IPADM_SUCCESS, "Operation succeeded" }, 64 { IPADM_FAILURE, "Operation failed" }, 65 { IPADM_EAUTH, "Insufficient user authorizations" }, 66 { IPADM_EPERM, "Permission denied" }, 67 { IPADM_NO_BUFS, "No buffer space available" }, 68 { IPADM_NO_MEMORY, "Insufficient memory" }, 69 { IPADM_BAD_ADDR, "Invalid address" }, 70 { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" }, 71 { IPADM_DAD_FOUND, "Duplicate address detected" }, 72 { IPADM_EXISTS, "Already exists" }, 73 { IPADM_IF_EXISTS, "Interface already exists" }, 74 { IPADM_ADDROBJ_EXISTS, "Address object already exists" }, 75 { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" }, 76 { IPADM_ENXIO, "Interface does not exist" }, 77 { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" }, 78 { IPADM_INVALID_ARG, "Invalid argument provided" }, 79 { IPADM_INVALID_NAME, "Invalid name" }, 80 { IPADM_DLPI_FAILURE, "Could not open DLPI link" }, 81 { IPADM_DLADM_FAILURE, "Datalink does not exist" }, 82 { IPADM_PROP_UNKNOWN, "Unknown property" }, 83 { IPADM_ERANGE, "Value is outside the allowed range" }, 84 { IPADM_ESRCH, "Value does not exist" }, 85 { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" }, 86 { IPADM_NOTFOUND, "Object not found" }, 87 { IPADM_IF_INUSE, "Interface already in use" }, 88 { IPADM_ADDR_INUSE, "Address already in use" }, 89 { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" }, 90 { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" }, 91 { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" }, 92 { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" }, 93 { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" }, 94 { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" }, 95 { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" }, 96 { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" }, 97 { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" }, 98 { IPADM_NOTSUP, "Operation not supported" }, 99 { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" }, 100 { IPADM_EBADE, "Invalid data exchange with daemon" } 101 }; 102 103 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors)) 104 105 ipadm_status_t 106 ipadm_errno2status(int error) 107 { 108 switch (error) { 109 case 0: 110 return (IPADM_SUCCESS); 111 case ENXIO: 112 return (IPADM_ENXIO); 113 case ENOMEM: 114 return (IPADM_NO_MEMORY); 115 case ENOBUFS: 116 return (IPADM_NO_BUFS); 117 case EINVAL: 118 return (IPADM_INVALID_ARG); 119 case EBUSY: 120 return (IPADM_IF_INUSE); 121 case EEXIST: 122 return (IPADM_EXISTS); 123 case EADDRNOTAVAIL: 124 return (IPADM_ADDR_NOTAVAIL); 125 case EADDRINUSE: 126 return (IPADM_ADDR_INUSE); 127 case ENOENT: 128 return (IPADM_NOTFOUND); 129 case ERANGE: 130 return (IPADM_ERANGE); 131 case EPERM: 132 return (IPADM_EPERM); 133 case ENOTSUP: 134 case EOPNOTSUPP: 135 return (IPADM_NOTSUP); 136 case EBADF: 137 return (IPADM_IPC_ERROR); 138 case EBADE: 139 return (IPADM_EBADE); 140 case ESRCH: 141 return (IPADM_ESRCH); 142 case EOVERFLOW: 143 return (IPADM_EOVERFLOW); 144 default: 145 return (IPADM_FAILURE); 146 } 147 } 148 149 /* 150 * Returns a message string for the given libipadm error status. 151 */ 152 const char * 153 ipadm_status2str(ipadm_status_t status) 154 { 155 int i; 156 157 for (i = 0; i < IPADM_NUM_ERRORS; i++) { 158 if (status == ipadm_errors[i].error_code) 159 return (dgettext(TEXT_DOMAIN, 160 ipadm_errors[i].error_desc)); 161 } 162 163 return (dgettext(TEXT_DOMAIN, "<unknown error>")); 164 } 165 166 /* 167 * Opens a handle to libipadm. 168 * Possible values for flags: 169 * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP. 170 * IPH_LEGACY: This is used whenever an application needs to provide a 171 * logical interface name while creating or deleting 172 * interfaces and static addresses. 173 * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties 174 * on reboot. 175 */ 176 ipadm_status_t 177 ipadm_open(ipadm_handle_t *handle, uint32_t flags) 178 { 179 ipadm_handle_t iph; 180 ipadm_status_t status = IPADM_SUCCESS; 181 zoneid_t zoneid; 182 ushort_t zflags; 183 int on = B_TRUE; 184 185 if (handle == NULL) 186 return (IPADM_INVALID_ARG); 187 *handle = NULL; 188 189 if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT)) 190 return (IPADM_INVALID_ARG); 191 192 if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL) 193 return (IPADM_NO_MEMORY); 194 iph->iph_sock = -1; 195 iph->iph_sock6 = -1; 196 iph->iph_door_fd = -1; 197 iph->iph_flags = flags; 198 (void) pthread_mutex_init(&iph->iph_lock, NULL); 199 200 if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 || 201 (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 202 goto errnofail; 203 } 204 205 /* 206 * We open a handle to libdladm here, to facilitate some daemons (like 207 * nwamd) which opens handle to libipadm before devfsadmd installs the 208 * right device permissions into the kernel and requires "all" 209 * privileges to open DLD_CONTROL_DEV. 210 * 211 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node 212 * and dladm_open() will fail. So, we avoid this by not calling 213 * dladm_open() for such zones. 214 */ 215 zoneid = getzoneid(); 216 if (zoneid != GLOBAL_ZONEID) { 217 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags, 218 sizeof (zflags)) < 0) { 219 goto errnofail; 220 } 221 } 222 if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) { 223 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) { 224 ipadm_close(iph); 225 return (IPADM_DLADM_FAILURE); 226 } 227 } else { 228 assert(zoneid != GLOBAL_ZONEID); 229 iph->iph_dlh = NULL; 230 } 231 if (flags & IPH_VRRP) { 232 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on, 233 sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET, 234 SO_VRRP, &on, sizeof (on)) < 0) { 235 goto errnofail; 236 } 237 } 238 *handle = iph; 239 return (status); 240 241 errnofail: 242 status = ipadm_errno2status(errno); 243 ipadm_close(iph); 244 return (status); 245 } 246 247 /* 248 * Closes and frees the libipadm handle. 249 */ 250 void 251 ipadm_close(ipadm_handle_t iph) 252 { 253 if (iph == NULL) 254 return; 255 if (iph->iph_sock != -1) 256 (void) close(iph->iph_sock); 257 if (iph->iph_sock6 != -1) 258 (void) close(iph->iph_sock6); 259 if (iph->iph_door_fd != -1) 260 (void) close(iph->iph_door_fd); 261 dladm_close(iph->iph_dlh); 262 (void) pthread_mutex_destroy(&iph->iph_lock); 263 free(iph); 264 } 265 266 /* 267 * Checks if the caller has the authorization to configure network 268 * interfaces. 269 */ 270 boolean_t 271 ipadm_check_auth(void) 272 { 273 struct passwd pwd; 274 char buf[NSS_BUFLEN_PASSWD]; 275 276 /* get the password entry for the given user ID */ 277 if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL) 278 return (B_FALSE); 279 280 /* check for presence of given authorization */ 281 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0); 282 } 283 284 /* 285 * Stores the index value of the interface in `ifname' for the address 286 * family `af' into the buffer pointed to by `index'. 287 */ 288 static ipadm_status_t 289 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af, 290 int *index) 291 { 292 struct lifreq lifr; 293 int sock; 294 295 bzero(&lifr, sizeof (lifr)); 296 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 297 if (af == AF_INET) 298 sock = iph->iph_sock; 299 else 300 sock = iph->iph_sock6; 301 302 if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0) 303 return (ipadm_errno2status(errno)); 304 *index = lifr.lifr_index; 305 306 return (IPADM_SUCCESS); 307 } 308 309 /* 310 * Maximum amount of time (in milliseconds) to wait for Duplicate Address 311 * Detection to complete in the kernel. 312 */ 313 #define DAD_WAIT_TIME 1000 314 315 /* 316 * Any time that flags are changed on an interface where either the new or the 317 * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to 318 * announce the new address added and its flag status. 319 * We wait here for that message and look for IFF_UP. 320 * If something's amiss with the kernel, though, we don't wait forever. 321 * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see 322 * it in the routing socket messages.) 323 */ 324 static ipadm_status_t 325 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af, 326 int rtsock) 327 { 328 struct pollfd fds[1]; 329 union { 330 struct if_msghdr ifm; 331 char buf[1024]; 332 } msg; 333 int index; 334 ipadm_status_t retv; 335 uint64_t flags; 336 hrtime_t starttime, now; 337 338 fds[0].fd = rtsock; 339 fds[0].events = POLLIN; 340 fds[0].revents = 0; 341 342 retv = i_ipadm_get_index(handle, lifname, af, &index); 343 if (retv != IPADM_SUCCESS) 344 return (retv); 345 346 starttime = gethrtime(); 347 for (;;) { 348 now = gethrtime(); 349 now = (now - starttime) / 1000000; 350 if (now >= DAD_WAIT_TIME) 351 break; 352 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0) 353 break; 354 if (read(rtsock, &msg, sizeof (msg)) <= 0) 355 break; 356 if (msg.ifm.ifm_type != RTM_NEWADDR) 357 continue; 358 /* Note that ifm_index is just 16 bits */ 359 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP)) 360 return (IPADM_SUCCESS); 361 } 362 363 retv = i_ipadm_get_flags(handle, lifname, af, &flags); 364 if (retv != IPADM_SUCCESS) 365 return (retv); 366 if (flags & IFF_DUPLICATE) 367 return (IPADM_DAD_FOUND); 368 369 return (IPADM_SUCCESS); 370 } 371 372 /* 373 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical 374 * interface in `lifname'. 375 * 376 * If the new flags value will transition the interface from "down" to "up" 377 * then duplicate address detection is performed by the kernel. This routine 378 * waits to get the outcome of that test. 379 */ 380 ipadm_status_t 381 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 382 uint64_t on_flags, uint64_t off_flags) 383 { 384 struct lifreq lifr; 385 uint64_t oflags; 386 ipadm_status_t ret; 387 int rtsock = -1; 388 int sock, err; 389 390 ret = i_ipadm_get_flags(iph, lifname, af, &oflags); 391 if (ret != IPADM_SUCCESS) 392 return (ret); 393 394 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 395 396 /* 397 * Any time flags are changed on an interface that has IFF_UP set, 398 * we get a routing socket message. We care about the status, 399 * though, only when the new flags are marked "up." 400 */ 401 if (!(oflags & IFF_UP) && (on_flags & IFF_UP)) 402 rtsock = socket(PF_ROUTE, SOCK_RAW, af); 403 404 oflags |= on_flags; 405 oflags &= ~off_flags; 406 bzero(&lifr, sizeof (lifr)); 407 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 408 lifr.lifr_flags = oflags; 409 if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 410 err = errno; 411 if (rtsock != -1) 412 (void) close(rtsock); 413 return (ipadm_errno2status(err)); 414 } 415 if (rtsock == -1) { 416 return (IPADM_SUCCESS); 417 } else { 418 /* Wait for DAD to complete. */ 419 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock); 420 (void) close(rtsock); 421 return (ret); 422 } 423 } 424 425 /* 426 * Returns the flags value for the logical interface in `lifname' 427 * in the buffer pointed to by `flags'. 428 */ 429 ipadm_status_t 430 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af, 431 uint64_t *flags) 432 { 433 struct lifreq lifr; 434 int sock; 435 436 bzero(&lifr, sizeof (lifr)); 437 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 438 if (af == AF_INET) 439 sock = iph->iph_sock; 440 else 441 sock = iph->iph_sock6; 442 443 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 444 return (ipadm_errno2status(errno)); 445 } 446 *flags = lifr.lifr_flags; 447 448 return (IPADM_SUCCESS); 449 } 450 451 /* 452 * Determines whether or not an interface name represents a loopback 453 * interface, before the interface has been plumbed. 454 * It is assumed that the interface name in `ifname' is of correct format 455 * as verified by ifparse_ifspec(). 456 * 457 * Returns: B_TRUE if loopback, B_FALSE if not. 458 */ 459 boolean_t 460 i_ipadm_is_loopback(const char *ifname) 461 { 462 int len = strlen(LOOPBACK_IF); 463 464 return (strncmp(ifname, LOOPBACK_IF, len) == 0 && 465 (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP)); 466 } 467 468 /* 469 * Determines whether or not an interface name represents a vni 470 * interface, before the interface has been plumbed. 471 * It is assumed that the interface name in `ifname' is of correct format 472 * as verified by ifparse_ifspec(). 473 * 474 * Returns: B_TRUE if vni, B_FALSE if not. 475 */ 476 boolean_t 477 i_ipadm_is_vni(const char *ifname) 478 { 479 ifspec_t ifsp; 480 481 return (ifparse_ifspec(ifname, &ifsp) && 482 strcmp(ifsp.ifsp_devnm, "vni") == 0); 483 } 484 485 /* 486 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel. 487 */ 488 boolean_t 489 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname) 490 { 491 dladm_status_t dlstatus; 492 datalink_class_t class; 493 iptun_params_t params; 494 datalink_id_t linkid; 495 496 if (iph->iph_dlh == NULL) { 497 assert(getzoneid() != GLOBAL_ZONEID); 498 return (B_FALSE); 499 } 500 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL, 501 &class, NULL); 502 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) { 503 params.iptun_param_linkid = linkid; 504 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms, 505 DLADM_OPT_ACTIVE); 506 if (dlstatus == DLADM_STATUS_OK && 507 params.iptun_param_type == IPTUN_TYPE_6TO4) { 508 return (B_TRUE); 509 } 510 } 511 return (B_FALSE); 512 } 513 514 /* 515 * Returns B_TRUE if `ifname' represents an IPMP underlying interface. 516 */ 517 boolean_t 518 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname) 519 { 520 struct lifreq lifr; 521 522 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 523 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) { 524 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME, 525 (caddr_t)&lifr) < 0) { 526 return (B_FALSE); 527 } 528 } 529 return (lifr.lifr_groupname[0] != '\0'); 530 } 531 532 /* 533 * Returns B_TRUE if `ifname' represents an IPMP meta-interface. 534 */ 535 boolean_t 536 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname) 537 { 538 uint64_t flags; 539 540 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS && 541 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS) 542 return (B_FALSE); 543 544 return ((flags & IFF_IPMP) != 0); 545 } 546 547 /* 548 * For a given interface name, ipadm_if_enabled() checks if v4 549 * or v6 or both IP interfaces exist in the active configuration. 550 */ 551 boolean_t 552 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af) 553 { 554 struct lifreq lifr; 555 int s4 = iph->iph_sock; 556 int s6 = iph->iph_sock6; 557 558 bzero(&lifr, sizeof (lifr)); 559 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 560 switch (af) { 561 case AF_INET: 562 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 563 return (B_TRUE); 564 break; 565 case AF_INET6: 566 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) 567 return (B_TRUE); 568 break; 569 case AF_UNSPEC: 570 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 || 571 ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) { 572 return (B_TRUE); 573 } 574 } 575 return (B_FALSE); 576 } 577 578 /* 579 * Apply the interface property by retrieving information from nvl. 580 */ 581 static ipadm_status_t 582 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl) 583 { 584 nvpair_t *nvp; 585 char *name, *pname = NULL; 586 char *protostr = NULL, *ifname = NULL, *pval = NULL; 587 uint_t proto; 588 int err = 0; 589 590 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 591 nvp = nvlist_next_nvpair(nvl, nvp)) { 592 name = nvpair_name(nvp); 593 if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 594 if ((err = nvpair_value_string(nvp, &ifname)) != 0) 595 break; 596 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) { 597 if ((err = nvpair_value_string(nvp, &protostr)) != 0) 598 break; 599 } else { 600 assert(!IPADM_PRIV_NVP(name)); 601 pname = name; 602 if ((err = nvpair_value_string(nvp, &pval)) != 0) 603 break; 604 } 605 } 606 if (err != 0) 607 return (ipadm_errno2status(err)); 608 proto = ipadm_str2proto(protostr); 609 return (ipadm_set_ifprop(iph, ifname, pname, pval, proto, 610 IPADM_OPT_ACTIVE)); 611 } 612 613 /* 614 * Instantiate the address object or set the address object property by 615 * retrieving the configuration from the nvlist `nvl'. 616 */ 617 ipadm_status_t 618 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl) 619 { 620 nvpair_t *nvp; 621 char *name; 622 char *aobjname = NULL, *pval = NULL, *ifname = NULL; 623 sa_family_t af = AF_UNSPEC; 624 ipadm_addr_type_t atype = IPADM_ADDR_NONE; 625 int err = 0; 626 ipadm_status_t status = IPADM_SUCCESS; 627 628 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 629 nvp = nvlist_next_nvpair(nvl, nvp)) { 630 name = nvpair_name(nvp); 631 if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 632 if ((err = nvpair_value_string(nvp, &ifname)) != 0) 633 break; 634 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 635 if ((err = nvpair_value_string(nvp, &aobjname)) != 0) 636 break; 637 } else if (i_ipadm_name2atype(name, &af, &atype)) { 638 break; 639 } else { 640 assert(!IPADM_PRIV_NVP(name)); 641 err = nvpair_value_string(nvp, &pval); 642 break; 643 } 644 } 645 if (err != 0) 646 return (ipadm_errno2status(err)); 647 648 switch (atype) { 649 case IPADM_ADDR_STATIC: 650 status = i_ipadm_enable_static(iph, ifname, nvl, af); 651 break; 652 case IPADM_ADDR_DHCP: 653 status = i_ipadm_enable_dhcp(iph, ifname, nvl); 654 if (status == IPADM_DHCP_IPC_TIMEOUT) 655 status = IPADM_SUCCESS; 656 break; 657 case IPADM_ADDR_IPV6_ADDRCONF: 658 status = i_ipadm_enable_addrconf(iph, ifname, nvl); 659 break; 660 case IPADM_ADDR_NONE: 661 status = ipadm_set_addrprop(iph, name, pval, aobjname, 662 IPADM_OPT_ACTIVE); 663 break; 664 } 665 666 return (status); 667 } 668 669 /* 670 * Instantiate the interface object by retrieving the configuration from 671 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration 672 * (interface properties and address objects on that interface) for the 673 * given `ifname'. 674 */ 675 ipadm_status_t 676 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl) 677 { 678 nvlist_t *nvl = NULL; 679 nvpair_t *nvp; 680 char *afstr; 681 ipadm_status_t status; 682 ipadm_status_t ret_status = IPADM_SUCCESS; 683 char newifname[LIFNAMSIZ]; 684 char *aobjstr; 685 686 (void) strlcpy(newifname, ifname, sizeof (newifname)); 687 /* 688 * First plumb the given interface and then apply all the persistent 689 * interface properties and then instantiate any persistent addresses 690 * objects on that interface. 691 */ 692 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL; 693 nvp = nvlist_next_nvpair(ifnvl, nvp)) { 694 if (nvpair_value_nvlist(nvp, &nvl) != 0) 695 continue; 696 697 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) { 698 status = i_ipadm_plumb_if(iph, newifname, atoi(afstr), 699 IPADM_OPT_ACTIVE); 700 /* 701 * If the interface is already plumbed, we should 702 * ignore this error because there might be address 703 * address objects on that interface that needs to 704 * be enabled again. 705 */ 706 if (status == IPADM_IF_EXISTS) 707 status = IPADM_SUCCESS; 708 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME, 709 &aobjstr) == 0) { 710 /* 711 * For a static address, we need to search for 712 * the prefixlen in the nvlist `ifnvl'. 713 */ 714 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) || 715 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) { 716 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl, 717 nvl, aobjstr); 718 if (status != IPADM_SUCCESS) 719 continue; 720 } 721 status = i_ipadm_init_addrobj(iph, nvl); 722 /* 723 * If this address is in use on some other interface, 724 * we want to record an error to be returned as 725 * a soft error and continue processing the rest of 726 * the addresses. 727 */ 728 if (status == IPADM_ADDR_NOTAVAIL) { 729 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED; 730 status = IPADM_SUCCESS; 731 } 732 } else { 733 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME)); 734 status = i_ipadm_init_ifprop(iph, nvl); 735 } 736 if (status != IPADM_SUCCESS) 737 return (status); 738 } 739 return (ret_status); 740 } 741 742 /* 743 * Retrieves the persistent configuration for the given interface(s) in `ifs' 744 * by contacting the daemon and dumps the information in `allifs'. 745 */ 746 ipadm_status_t 747 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs) 748 { 749 nvlist_t *nvl = NULL; 750 size_t nvlsize, bufsize; 751 ipmgmt_initif_arg_t *iargp; 752 char *buf = NULL, *nvlbuf = NULL; 753 ipmgmt_get_rval_t *rvalp = NULL; 754 int err; 755 ipadm_status_t status = IPADM_SUCCESS; 756 757 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0) 758 return (ipadm_errno2status(err)); 759 760 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0); 761 if (err != 0) { 762 status = ipadm_errno2status(err); 763 goto done; 764 } 765 bufsize = sizeof (*iargp) + nvlsize; 766 if ((buf = malloc(bufsize)) == NULL) { 767 status = ipadm_errno2status(errno); 768 goto done; 769 } 770 771 /* populate the door_call argument structure */ 772 iargp = (void *)buf; 773 iargp->ia_cmd = IPMGMT_CMD_INITIF; 774 iargp->ia_flags = 0; 775 iargp->ia_family = AF_UNSPEC; 776 iargp->ia_nvlsize = nvlsize; 777 (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize); 778 779 if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) { 780 status = ipadm_errno2status(errno); 781 goto done; 782 } 783 if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp, 784 sizeof (*rvalp), B_TRUE)) != 0) { 785 status = ipadm_errno2status(err); 786 goto done; 787 } 788 nvlsize = rvalp->ir_nvlsize; 789 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t); 790 791 /* 792 * nvlbuf contains a list of nvlists, each of which represents 793 * configuration information for the given interface(s) 794 */ 795 err = nvlist_unpack(nvlbuf, nvlsize, allifs, NV_ENCODE_NATIVE); 796 if (err != 0) 797 status = ipadm_errno2status(err); 798 done: 799 nvlist_free(nvl); 800 free(buf); 801 free(nvlbuf); 802 free(rvalp); 803 return (status); 804 } 805 806 /* 807 * Returns B_FALSE if 808 * (1) `ifname' is NULL or has no string or has a string of invalid length 809 * (2) ifname is a logical interface and IPH_LEGACY is not set, or 810 */ 811 boolean_t 812 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname) 813 { 814 ifspec_t ifsp; 815 816 if (ifname == NULL || ifname[0] == '\0' || 817 !ifparse_ifspec(ifname, &ifsp)) 818 return (B_FALSE); 819 if (ifsp.ifsp_lunvalid) 820 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY)); 821 return (B_TRUE); 822 } 823 824 /* 825 * Wrapper for sending a non-transparent I_STR ioctl(). 826 * Returns: Result from ioctl(). 827 */ 828 int 829 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen) 830 { 831 struct strioctl ioc; 832 833 (void) memset(&ioc, 0, sizeof (ioc)); 834 ioc.ic_cmd = cmd; 835 ioc.ic_timout = 0; 836 ioc.ic_len = buflen; 837 ioc.ic_dp = buf; 838 839 return (ioctl(s, I_STR, (char *)&ioc)); 840 } 841 842 /* 843 * Make a door call to the server and checks if the door call succeeded or not. 844 * `is_varsize' specifies that the data returned by ipmgmtd daemon is of 845 * variable size and door will allocate buffer using mmap(). In such cases 846 * we re-allocate the required memory,n assign it to `rbufp', copy the data to 847 * `rbufp' and then call munmap() (see below). 848 * 849 * It also checks to see if the server side procedure ran successfully by 850 * checking for ir_err. Therefore, for some callers who just care about the 851 * return status can set `rbufp' to NULL and set `rsize' to 0. 852 */ 853 int 854 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp, 855 size_t rsize, boolean_t is_varsize) 856 { 857 door_arg_t darg; 858 int err; 859 ipmgmt_retval_t rval, *rvalp; 860 boolean_t reopen = B_FALSE; 861 862 if (rbufp == NULL) { 863 rvalp = &rval; 864 rbufp = (void **)&rvalp; 865 rsize = sizeof (rval); 866 } 867 868 darg.data_ptr = arg; 869 darg.data_size = asize; 870 darg.desc_ptr = NULL; 871 darg.desc_num = 0; 872 darg.rbuf = *rbufp; 873 darg.rsize = rsize; 874 875 reopen: 876 (void) pthread_mutex_lock(&iph->iph_lock); 877 /* The door descriptor is opened if it isn't already */ 878 if (iph->iph_door_fd == -1) { 879 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) { 880 err = errno; 881 (void) pthread_mutex_unlock(&iph->iph_lock); 882 return (err); 883 } 884 } 885 (void) pthread_mutex_unlock(&iph->iph_lock); 886 887 if (door_call(iph->iph_door_fd, &darg) == -1) { 888 /* 889 * Stale door descriptor is possible if ipmgmtd was restarted 890 * since last iph_door_fd was opened, so try re-opening door 891 * descriptor. 892 */ 893 if (!reopen && errno == EBADF) { 894 (void) close(iph->iph_door_fd); 895 iph->iph_door_fd = -1; 896 reopen = B_TRUE; 897 goto reopen; 898 } 899 return (errno); 900 } 901 err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err; 902 if (darg.rbuf != *rbufp) { 903 /* 904 * if the caller is expecting the result to fit in specified 905 * buffer then return failure. 906 */ 907 if (!is_varsize) 908 err = EBADE; 909 /* 910 * The size of the buffer `*rbufp' was not big enough 911 * and the door itself allocated buffer, for us. We will 912 * hit this, on several occasion as for some cases 913 * we cannot predict the size of the return structure. 914 * Reallocate the buffer `*rbufp' and memcpy() the contents 915 * to new buffer. 916 */ 917 if (err == 0) { 918 void *newp; 919 920 /* allocated memory will be freed by the caller */ 921 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) { 922 err = ENOMEM; 923 } else { 924 *rbufp = newp; 925 (void) memcpy(*rbufp, darg.rbuf, darg.rsize); 926 } 927 } 928 /* munmap() the door buffer */ 929 (void) munmap(darg.rbuf, darg.rsize); 930 } else { 931 if (darg.rsize != rsize) 932 err = EBADE; 933 } 934 return (err); 935 } 936