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