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