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