1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <errno.h> 27 #include <sys/sockio.h> 28 #include <string.h> 29 #include <assert.h> 30 #include <unistd.h> 31 #include <stropts.h> 32 #include <strings.h> 33 #include <libdlpi.h> 34 #include <libdllink.h> 35 #include <libinetutil.h> 36 #include <inet/ip.h> 37 #include <limits.h> 38 #include <zone.h> 39 #include <ipadm_ndpd.h> 40 #include "libipadm_impl.h" 41 42 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int); 43 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *, 44 uint64_t, int, uint32_t); 45 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *, 46 sa_family_t); 47 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *, 48 sa_family_t); 49 50 /* 51 * Returns B_FALSE if the interface in `ifname' has at least one address that is 52 * IFF_UP in the addresses in `ifa'. 53 */ 54 static boolean_t 55 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa) 56 { 57 struct ifaddrs *ifap; 58 char cifname[LIFNAMSIZ]; 59 char *sep; 60 61 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 62 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname)); 63 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL) 64 *sep = '\0'; 65 /* 66 * If this condition is true, there is at least one 67 * address that is IFF_UP. So, we need to return B_FALSE. 68 */ 69 if (strcmp(cifname, ifname) == 0 && 70 (ifap->ifa_flags & IFF_UP)) { 71 return (B_FALSE); 72 } 73 } 74 /* We did not find any IFF_UP addresses. */ 75 return (B_TRUE); 76 } 77 78 /* 79 * Retrieves the information for the interface `ifname' from active 80 * config if `ifname' is specified and returns the result in the list `if_info'. 81 * Otherwise, it retrieves the information for all the interfaces in 82 * the active config and returns the result in the list `if_info'. 83 */ 84 static ipadm_status_t 85 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname, 86 ipadm_if_info_t **if_info, int64_t lifc_flags) 87 { 88 struct lifreq *buf; 89 struct lifreq *lifrp; 90 struct lifreq lifrl; 91 ipadm_if_info_t *last = NULL; 92 ipadm_if_info_t *ifp; 93 int s; 94 int n; 95 int numifs; 96 ipadm_status_t status; 97 98 *if_info = NULL; 99 /* 100 * Get information for all interfaces. 101 */ 102 if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0) 103 return (ipadm_errno2status(errno)); 104 105 lifrp = buf; 106 for (n = 0; n < numifs; n++, lifrp++) { 107 /* Skip interfaces with logical num != 0 */ 108 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0) 109 continue; 110 /* 111 * Skip the current interface if a specific `ifname' has 112 * been requested and current interface does not match 113 * `ifname'. 114 */ 115 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0) 116 continue; 117 /* 118 * Check if the interface already exists in our list. 119 * If it already exists, we need to update its flags. 120 */ 121 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) { 122 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0) 123 break; 124 } 125 if (ifp == NULL) { 126 ifp = calloc(1, sizeof (ipadm_if_info_t)); 127 if (ifp == NULL) { 128 status = ipadm_errno2status(errno); 129 goto fail; 130 } 131 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name, 132 sizeof (ifp->ifi_name)); 133 /* Update the `ifi_next' pointer for this new node */ 134 if (*if_info == NULL) 135 *if_info = ifp; 136 else 137 last->ifi_next = ifp; 138 last = ifp; 139 } 140 141 /* 142 * Retrieve the flags for the interface by doing a 143 * SIOCGLIFFLAGS to populate the `ifi_cflags' field. 144 */ 145 (void) strlcpy(lifrl.lifr_name, 146 lifrp->lifr_name, sizeof (lifrl.lifr_name)); 147 s = (lifrp->lifr_addr.ss_family == AF_INET) ? 148 iph->iph_sock : iph->iph_sock6; 149 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) 150 continue; 151 if (lifrl.lifr_flags & IFF_BROADCAST) 152 ifp->ifi_cflags |= IFIF_BROADCAST; 153 if (lifrl.lifr_flags & IFF_MULTICAST) 154 ifp->ifi_cflags |= IFIF_MULTICAST; 155 if (lifrl.lifr_flags & IFF_POINTOPOINT) 156 ifp->ifi_cflags |= IFIF_POINTOPOINT; 157 if (lifrl.lifr_flags & IFF_VIRTUAL) 158 ifp->ifi_cflags |= IFIF_VIRTUAL; 159 if (lifrl.lifr_flags & IFF_IPMP) 160 ifp->ifi_cflags |= IFIF_IPMP; 161 if (lifrl.lifr_flags & IFF_STANDBY) 162 ifp->ifi_cflags |= IFIF_STANDBY; 163 if (lifrl.lifr_flags & IFF_INACTIVE) 164 ifp->ifi_cflags |= IFIF_INACTIVE; 165 if (lifrl.lifr_flags & IFF_VRRP) 166 ifp->ifi_cflags |= IFIF_VRRP; 167 if (lifrl.lifr_flags & IFF_NOACCEPT) 168 ifp->ifi_cflags |= IFIF_NOACCEPT; 169 if (lifrl.lifr_flags & IFF_IPV4) 170 ifp->ifi_cflags |= IFIF_IPV4; 171 if (lifrl.lifr_flags & IFF_IPV6) 172 ifp->ifi_cflags |= IFIF_IPV6; 173 } 174 free(buf); 175 return (IPADM_SUCCESS); 176 fail: 177 free(buf); 178 ipadm_free_if_info(*if_info); 179 *if_info = NULL; 180 return (status); 181 } 182 183 /* 184 * Returns the interface information for `ifname' in `if_info' from persistent 185 * config if `ifname' is non-null. Otherwise, it returns all the interfaces 186 * from persistent config in `if_info'. 187 */ 188 static ipadm_status_t 189 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname, 190 ipadm_if_info_t **if_info) 191 { 192 ipadm_status_t status = IPADM_SUCCESS; 193 ipmgmt_getif_arg_t getif; 194 ipmgmt_getif_rval_t *rvalp; 195 ipadm_if_info_t *ifp, *curr, *prev = NULL; 196 int i = 0, err = 0; 197 198 bzero(&getif, sizeof (getif)); 199 if (ifname != NULL) 200 (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ); 201 getif.ia_cmd = IPMGMT_CMD_GETIF; 202 203 *if_info = NULL; 204 205 if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL) 206 return (ipadm_errno2status(errno)); 207 err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp, 208 sizeof (*rvalp), B_TRUE); 209 if (err == ENOENT) { 210 free(rvalp); 211 if (ifname != NULL) 212 return (ipadm_errno2status(err)); 213 return (IPADM_SUCCESS); 214 } else if (err != 0) { 215 free(rvalp); 216 return (ipadm_errno2status(err)); 217 } 218 219 ifp = rvalp->ir_ifinfo; 220 for (i = 0; i < rvalp->ir_ifcnt; i++) { 221 ifp = rvalp->ir_ifinfo + i; 222 if ((curr = malloc(sizeof (*curr))) == NULL) { 223 status = ipadm_errno2status(errno); 224 ipadm_free_if_info(prev); 225 break; 226 } 227 (void) bcopy(ifp, curr, sizeof (*curr)); 228 curr->ifi_next = prev; 229 prev = curr; 230 } 231 *if_info = curr; 232 free(rvalp); 233 return (status); 234 } 235 236 /* 237 * Collects information for `ifname' if one is specified from both 238 * active and persistent config in `if_info'. If no `ifname' is specified, 239 * this returns all the interfaces in active and persistent config in 240 * `if_info'. 241 */ 242 ipadm_status_t 243 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname, 244 ipadm_if_info_t **if_info, int64_t lifc_flags) 245 { 246 ipadm_status_t status; 247 ipadm_if_info_t *aifinfo = NULL; 248 ipadm_if_info_t *pifinfo = NULL; 249 ipadm_if_info_t *aifp; 250 ipadm_if_info_t *pifp; 251 ipadm_if_info_t *last = NULL; 252 struct ifaddrs *ifa; 253 struct ifaddrs *ifap; 254 255 /* 256 * Retrive the information for the requested `ifname' or all 257 * interfaces from active configuration. 258 */ 259 retry: 260 status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags); 261 if (status != IPADM_SUCCESS) 262 return (status); 263 /* Get the interface state for each interface in `aifinfo'. */ 264 if (aifinfo != NULL) { 265 /* We need all addresses to get the interface state */ 266 if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY| 267 LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) { 268 status = ipadm_errno2status(errno); 269 goto fail; 270 } 271 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 272 /* 273 * Find the `ifaddrs' structure from `ifa' 274 * for this interface. We need the IFF_* flags 275 * to find the interface state. 276 */ 277 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 278 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0) 279 break; 280 } 281 if (ifap == NULL) { 282 /* 283 * The interface might have been removed 284 * from kernel. Retry getting all the active 285 * interfaces. 286 */ 287 freeifaddrs(ifa); 288 ipadm_free_if_info(aifinfo); 289 aifinfo = NULL; 290 goto retry; 291 } 292 if (!(ifap->ifa_flags & IFF_RUNNING) || 293 (ifap->ifa_flags & IFF_FAILED)) 294 aifp->ifi_state = IFIS_FAILED; 295 else if (ifap->ifa_flags & IFF_OFFLINE) 296 aifp->ifi_state = IFIS_OFFLINE; 297 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa)) 298 aifp->ifi_state = IFIS_DOWN; 299 else 300 aifp->ifi_state = IFIS_OK; 301 if (aifp->ifi_next == NULL) 302 last = aifp; 303 } 304 freeifaddrs(ifa); 305 } 306 /* 307 * Get the persistent interface information in `pifinfo'. 308 */ 309 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo); 310 if (status == IPADM_NOTFOUND) { 311 *if_info = aifinfo; 312 return (IPADM_SUCCESS); 313 } 314 if (status != IPADM_SUCCESS) 315 goto fail; 316 /* 317 * If a persistent interface is also found in `aifinfo', update 318 * its entry in `aifinfo' with the persistent information from 319 * `pifinfo'. If an interface is found in `pifinfo', but not in 320 * `aifinfo', it means that this interface was disabled. We should 321 * add this interface to `aifinfo' and set it state to IFIF_DISABLED. 322 */ 323 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) { 324 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) { 325 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) { 326 aifp->ifi_pflags = pifp->ifi_pflags; 327 break; 328 } 329 } 330 if (aifp == NULL) { 331 aifp = malloc(sizeof (ipadm_if_info_t)); 332 if (aifp == NULL) { 333 status = ipadm_errno2status(errno); 334 goto fail; 335 } 336 *aifp = *pifp; 337 aifp->ifi_next = NULL; 338 aifp->ifi_state = IFIS_DISABLED; 339 if (last != NULL) 340 last->ifi_next = aifp; 341 else 342 aifinfo = aifp; 343 last = aifp; 344 } 345 } 346 *if_info = aifinfo; 347 ipadm_free_if_info(pifinfo); 348 return (IPADM_SUCCESS); 349 fail: 350 *if_info = NULL; 351 ipadm_free_if_info(aifinfo); 352 ipadm_free_if_info(pifinfo); 353 return (status); 354 } 355 356 int 357 i_ipadm_get_lnum(const char *ifname) 358 { 359 char *num = strrchr(ifname, IPADM_LOGICAL_SEP); 360 361 if (num == NULL) 362 return (0); 363 364 return (atoi(++num)); 365 } 366 367 /* 368 * Sets the output argument `exists' to true or false based on whether 369 * any persistent configuration is available for `ifname' and returns 370 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved, 371 * `exists' is unmodified and an error status is returned. 372 */ 373 ipadm_status_t 374 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af, 375 boolean_t *exists) 376 { 377 ipadm_if_info_t *ifinfo; 378 ipadm_status_t status; 379 380 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo); 381 if (status == IPADM_SUCCESS) { 382 *exists = ((af == AF_INET && 383 (ifinfo->ifi_pflags & IFIF_IPV4)) || 384 (af == AF_INET6 && 385 (ifinfo->ifi_pflags & IFIF_IPV6))); 386 free(ifinfo); 387 } else if (status == IPADM_NOTFOUND) { 388 status = IPADM_SUCCESS; 389 *exists = B_FALSE; 390 } 391 return (status); 392 } 393 394 /* 395 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream 396 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let 397 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at 398 * the bottom of the stream for tunneling interfaces. 399 */ 400 ipadm_status_t 401 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd) 402 { 403 int err; 404 405 if ((*fd = open(udp_dev_name, O_RDWR)) == -1) 406 return (ipadm_errno2status(errno)); 407 408 /* 409 * Pop off all undesired modules (note that the user may have 410 * configured autopush to add modules above udp), and push the 411 * arp module onto the resulting stream. This is used to make 412 * IP+ARP be able to atomically track the muxid for the I_PLINKed 413 * STREAMS, thus it isn't related to ARP running the ARP protocol. 414 */ 415 while (ioctl(*fd, I_POP, 0) != -1) 416 ; 417 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1) 418 return (IPADM_SUCCESS); 419 err = errno; 420 (void) close(*fd); 421 422 return (ipadm_errno2status(err)); 423 } 424 425 /* 426 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an 427 * underlying interface in an ipmp group G is plumbed for an address family, 428 * but the meta-interface for the other address family `af' does not exist 429 * yet for the group G. If `af' is IPv6, we need to bring up the 430 * link-local address. 431 */ 432 static ipadm_status_t 433 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af, 434 const char *grname, uint32_t ipadm_flags) 435 { 436 ipadm_status_t status; 437 struct lifreq lifr; 438 int sock; 439 int err; 440 441 assert(ipadm_flags & IPADM_OPT_IPMP); 442 443 /* Create the ipmp underlying interface */ 444 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags); 445 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) 446 return (status); 447 448 /* 449 * To preserve backward-compatibility, always bring up the link-local 450 * address for implicitly-created IPv6 IPMP interfaces. 451 */ 452 if (af == AF_INET6) 453 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0); 454 455 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 456 /* 457 * If the caller requested a different group name, issue a 458 * SIOCSLIFGROUPNAME on the new IPMP interface. 459 */ 460 bzero(&lifr, sizeof (lifr)); 461 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 462 if (strcmp(lifr.lifr_name, grname) != 0) { 463 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ); 464 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) { 465 err = errno; 466 /* Remove the interface we created. */ 467 if (status == IPADM_SUCCESS) { 468 (void) i_ipadm_delete_if(iph, ifname, af, 469 ipadm_flags); 470 } 471 return (ipadm_errno2status(err)); 472 } 473 } 474 475 return (IPADM_SUCCESS); 476 } 477 478 /* 479 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address 480 * family. If so, create a matching IPMP group for address family `af'. 481 */ 482 static ipadm_status_t 483 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af) 484 { 485 lifgroupinfo_t lifgr; 486 ipadm_status_t status = IPADM_SUCCESS; 487 struct lifreq lifr; 488 int other_af_sock; 489 490 assert(af == AF_INET || af == AF_INET6); 491 492 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock); 493 494 /* 495 * iph is the handle for the interface that we are trying to plumb. 496 * other_af_sock is the socket for the "other" address family. 497 */ 498 bzero(&lifr, sizeof (lifr)); 499 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 500 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0) 501 return (IPADM_SUCCESS); 502 503 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ); 504 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0) 505 return (IPADM_SUCCESS); 506 507 /* 508 * If `ifname' *is* the IPMP group interface, or if the relevant 509 * address family is already configured, then there's nothing to do. 510 */ 511 if (strcmp(lifgr.gi_grifname, ifname) == 0 || 512 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) { 513 return (IPADM_SUCCESS); 514 } 515 516 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af, 517 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP); 518 return (status); 519 } 520 521 /* 522 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd. 523 */ 524 static ipadm_status_t 525 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd) 526 { 527 struct lifreq lifr; 528 ifspec_t ifsp; 529 530 bzero(&lifr, sizeof (lifr)); 531 (void) ifparse_ifspec(ifname, &ifsp); 532 lifr.lifr_ppa = ifsp.ifsp_ppa; 533 lifr.lifr_flags = flags; 534 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 535 /* 536 * Tell ARP the name and unit number for this interface. 537 * Note that arp has no support for transparent ioctls. 538 */ 539 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr, 540 sizeof (lifr)) == -1) { 541 return (ipadm_errno2status(errno)); 542 } 543 return (IPADM_SUCCESS); 544 } 545 546 /* 547 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in 548 * `ipadm_flags', then a ppa will be generated. `newif' will be updated 549 * with the generated ppa. 550 */ 551 static ipadm_status_t 552 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags, 553 int fd, uint32_t ipadm_flags) 554 { 555 struct lifreq lifr; 556 ipadm_status_t status = IPADM_SUCCESS; 557 int err = 0; 558 sa_family_t af; 559 int ppa; 560 ifspec_t ifsp; 561 boolean_t valid_if; 562 563 bzero(&lifr, sizeof (lifr)); 564 if (ipadm_flags & IPADM_OPT_GENPPA) { 565 /* 566 * We'd like to just set lifr_ppa to UINT_MAX and have the 567 * kernel pick a PPA. Unfortunately, that would mishandle 568 * two cases: 569 * 570 * 1. If the PPA is available but the groupname is taken 571 * (e.g., the "ipmp2" IP interface name is available 572 * but the "ipmp2" groupname is taken) then the 573 * auto-assignment by the kernel will fail. 574 * 575 * 2. If we're creating (e.g.) an IPv6-only IPMP 576 * interface, and there's already an IPv4-only IPMP 577 * interface, the kernel will allow us to accidentally 578 * reuse the IPv6 IPMP interface name (since 579 * SIOCSLIFNAME uniqueness is per-interface-type). 580 * This will cause administrative confusion. 581 * 582 * Thus, we instead take a brute-force approach of checking 583 * whether the IPv4 or IPv6 name is already in-use before 584 * attempting the SIOCSLIFNAME. As per (1) above, the 585 * SIOCSLIFNAME may still fail, in which case we just proceed 586 * to the next one. If this approach becomes too slow, we 587 * can add a new SIOC* to handle this case in the kernel. 588 */ 589 for (ppa = 0; ppa < UINT_MAX; ppa++) { 590 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d", 591 ifname, ppa); 592 593 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 || 594 errno != ENXIO) 595 continue; 596 597 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 || 598 errno != ENXIO) 599 continue; 600 601 lifr.lifr_ppa = ppa; 602 lifr.lifr_flags = flags; 603 604 err = ioctl(fd, SIOCSLIFNAME, &lifr); 605 if (err != -1 || errno != EEXIST) 606 break; 607 } 608 if (err == -1) { 609 status = ipadm_errno2status(errno); 610 } else { 611 /* 612 * PPA has been successfully established. 613 * Update `newif' with the ppa. 614 */ 615 assert(newif != NULL); 616 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname, 617 ppa) >= LIFNAMSIZ) 618 return (IPADM_INVALID_ARG); 619 } 620 } else { 621 /* We should have already validated the interface name. */ 622 valid_if = ifparse_ifspec(ifname, &ifsp); 623 assert(valid_if); 624 625 /* 626 * Before we call SIOCSLIFNAME, ensure that the IPMP group 627 * interface for this address family exists. Otherwise, the 628 * kernel will kick the interface out of the group when we do 629 * the SIOCSLIFNAME. 630 * 631 * Example: suppose bge0 is plumbed for IPv4 and in group "a". 632 * If we're now plumbing bge0 for IPv6, but the IPMP group 633 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME 634 * will kick bge0 out of group "a", which is undesired. 635 */ 636 if (flags & IFF_IPV4) 637 af = AF_INET; 638 else 639 af = AF_INET6; 640 status = i_ipadm_create_ipmp_peer(iph, ifname, af); 641 if (status != IPADM_SUCCESS) 642 return (status); 643 lifr.lifr_ppa = ifsp.ifsp_ppa; 644 lifr.lifr_flags = flags; 645 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 646 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1) 647 status = ipadm_errno2status(errno); 648 } 649 650 return (status); 651 } 652 653 /* 654 * Plumbs the interface `ifname' for the address family `af'. It also persists 655 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'. 656 */ 657 ipadm_status_t 658 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 659 uint32_t ipadm_flags) 660 { 661 int ip_muxid; 662 int mux_fd = -1, ip_fd, arp_fd; 663 char *udp_dev_name; 664 dlpi_handle_t dh_arp = NULL, dh_ip; 665 uint64_t ifflags; 666 struct lifreq lifr; 667 uint_t dlpi_flags; 668 ipadm_status_t status = IPADM_SUCCESS; 669 char *linkname; 670 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 671 zoneid_t zoneid; 672 char newif[LIFNAMSIZ]; 673 char lifname[LIFNAMSIZ]; 674 datalink_id_t linkid; 675 int sock; 676 boolean_t islo; 677 boolean_t is_persistent = 678 ((ipadm_flags & IPADM_OPT_PERSIST) != 0); 679 uint32_t dlflags; 680 dladm_status_t dlstatus; 681 682 if (iph->iph_dlh != NULL) { 683 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, 684 &dlflags, NULL, NULL); 685 } 686 /* 687 * If we're in the global zone and we're plumbing a datalink, make 688 * sure that the datalink is not assigned to a non-global zone. Note 689 * that the non-global zones don't need this check, because zoneadm 690 * has taken care of this when the zones boot. 691 */ 692 if (getzoneid() == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) { 693 zoneid = ALL_ZONES; 694 if (zone_check_datalink(&zoneid, linkid) == 0) { 695 /* interface is in use by a non-global zone. */ 696 return (IPADM_IF_INUSE); 697 } 698 } 699 700 /* loopback interfaces are just added as logical interface */ 701 bzero(&lifr, sizeof (lifr)); 702 islo = i_ipadm_is_loopback(ifname); 703 if (islo || i_ipadm_get_lnum(ifname) != 0) { 704 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 705 if (af == AF_INET) 706 sock = iph->iph_sock; 707 else 708 sock = iph->iph_sock6; 709 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) 710 return (IPADM_IF_EXISTS); 711 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 712 return (ipadm_errno2status(errno)); 713 714 /* 715 * By default, kernel configures 127.0.0.1 on the loopback 716 * interface. Replace this with 0.0.0.0 to be consistent 717 * with interface creation on other physical interfaces. 718 */ 719 if (islo && !legacy) { 720 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 721 lifr.lifr_addr.ss_family = af; 722 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 723 return (ipadm_errno2status(errno)); 724 if (is_persistent) { 725 status = i_ipadm_persist_if(iph, ifname, af); 726 if (status != IPADM_SUCCESS) { 727 (void) i_ipadm_delete_if(iph, ifname, 728 af, IPADM_OPT_ACTIVE); 729 } 730 } 731 } 732 return (status); 733 } 734 735 dlpi_flags = DLPI_NOATTACH; 736 737 /* 738 * If IPADM_OPT_IPMP is specified, then this is a request 739 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply 740 * pass "ipmpstub0" as devname since an admin *could* have a normal 741 * vanity-named link named "ipmpstub0" that they'd like to plumb.) 742 */ 743 if (ipadm_flags & IPADM_OPT_IPMP) { 744 dlpi_flags |= DLPI_DEVONLY; 745 linkname = "ipmpstub0"; 746 } else { 747 /* 748 * Verify that the user is not creating a persistent 749 * IP interface on a non-persistent data-link. 750 */ 751 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK && 752 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) { 753 return (IPADM_TEMPORARY_OBJ); 754 } 755 linkname = ifname; 756 } 757 758 /* 759 * We use DLPI_NOATTACH because the ip module will do the attach 760 * itself for DLPI style-2 devices. 761 */ 762 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS) 763 return (IPADM_DLPI_FAILURE); 764 ip_fd = dlpi_fd(dh_ip); 765 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) { 766 status = ipadm_errno2status(errno); 767 goto done; 768 } 769 770 /* 771 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications 772 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL. 773 */ 774 ifflags = 0; 775 776 /* Set the name string and the IFF_IPV* flag */ 777 if (af == AF_INET) { 778 ifflags = IFF_IPV4; 779 } else { 780 ifflags = IFF_IPV6; 781 /* 782 * With the legacy method, the link-local address should be 783 * configured as part of the interface plumb, using the default 784 * token. If IPH_LEGACY is not specified, we want to set :: as 785 * the address and require the admin to explicitly call 786 * ipadm_create_addr() with the address object type set to 787 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address 788 * as well as the autoconfigured addresses. 789 */ 790 if (!legacy && !i_ipadm_is_6to4(iph, ifname)) 791 ifflags |= IFF_NOLINKLOCAL; 792 } 793 (void) strlcpy(newif, ifname, sizeof (newif)); 794 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd, 795 ipadm_flags); 796 if (status != IPADM_SUCCESS) 797 goto done; 798 799 /* Get the full set of existing flags for this stream */ 800 status = i_ipadm_get_flags(iph, newif, af, &ifflags); 801 if (status != IPADM_SUCCESS) 802 goto done; 803 804 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME); 805 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 806 if (status != IPADM_SUCCESS) 807 goto done; 808 809 /* Check if arp is not needed */ 810 if (ifflags & (IFF_NOARP|IFF_IPV6)) { 811 /* 812 * PLINK the interface stream so that the application can exit 813 * without tearing down the stream. 814 */ 815 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) 816 status = ipadm_errno2status(errno); 817 goto done; 818 } 819 820 /* 821 * This interface does use ARP, so set up a separate stream 822 * from the interface to ARP. 823 * 824 * We use DLPI_NOATTACH because the arp module will do the attach 825 * itself for DLPI style-2 devices. 826 */ 827 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) { 828 status = IPADM_DLPI_FAILURE; 829 goto done; 830 } 831 832 arp_fd = dlpi_fd(dh_arp); 833 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) { 834 status = ipadm_errno2status(errno); 835 goto done; 836 } 837 838 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd); 839 if (status != IPADM_SUCCESS) 840 goto done; 841 /* 842 * PLINK the IP and ARP streams so that ifconfig can exit 843 * without tearing down the stream. 844 */ 845 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 846 status = ipadm_errno2status(errno); 847 goto done; 848 } 849 850 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) { 851 status = ipadm_errno2status(errno); 852 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 853 } 854 855 done: 856 dlpi_close(dh_ip); 857 if (dh_arp != NULL) 858 dlpi_close(dh_arp); 859 860 if (mux_fd != -1) 861 (void) close(mux_fd); 862 863 if (status == IPADM_SUCCESS) { 864 /* copy back new ifname */ 865 (void) strlcpy(ifname, newif, LIFNAMSIZ); 866 /* 867 * If it is a 6to4 tunnel, create a default 868 * addrobj name for the default address on the 0'th 869 * logical interface and set IFF_UP in the interface flags. 870 */ 871 if (i_ipadm_is_6to4(iph, ifname)) { 872 struct ipadm_addrobj_s addr; 873 874 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC); 875 addr.ipadm_af = af; 876 status = i_ipadm_lookupadd_addrobj(iph, &addr); 877 if (status != IPADM_SUCCESS) 878 return (status); 879 status = ipadm_add_aobjname(iph, ifname, 880 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0); 881 if (status != IPADM_SUCCESS) 882 return (status); 883 addr.ipadm_lifnum = 0; 884 i_ipadm_addrobj2lifname(&addr, lifname, 885 sizeof (lifname)); 886 status = i_ipadm_set_flags(iph, lifname, af, 887 IFF_UP, 0); 888 if (status != IPADM_SUCCESS) 889 return (status); 890 } else { 891 /* 892 * Prevent static IPv6 addresses from triggering 893 * autoconf. This does not have to be done for 894 * 6to4 tunnel interfaces, since in.ndpd will 895 * not autoconfigure those interfaces. 896 */ 897 if (af == AF_INET6 && !legacy) 898 (void) i_ipadm_disable_autoconf(newif); 899 } 900 901 /* 902 * If IPADM_OPT_PERSIST was set in flags, store the 903 * interface in persistent DB. 904 */ 905 if (is_persistent) { 906 status = i_ipadm_persist_if(iph, newif, af); 907 if (status != IPADM_SUCCESS) { 908 (void) i_ipadm_delete_if(iph, newif, af, 909 IPADM_OPT_ACTIVE); 910 } 911 } 912 } 913 if (status == IPADM_EXISTS) 914 status = IPADM_IF_EXISTS; 915 return (status); 916 } 917 918 /* 919 * Unplumbs the interface in `ifname' of family `af'. 920 */ 921 ipadm_status_t 922 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) 923 { 924 int ip_muxid, arp_muxid; 925 int mux_fd = -1; 926 int muxid_fd = -1; 927 char *udp_dev_name; 928 uint64_t flags; 929 boolean_t changed_arp_muxid = B_FALSE; 930 int save_errno; 931 struct lifreq lifr; 932 ipadm_status_t ret = IPADM_SUCCESS; 933 int sock; 934 lifgroupinfo_t lifgr; 935 ifaddrlistx_t *ifaddrs, *ifaddrp; 936 boolean_t v6 = (af == AF_INET6); 937 938 /* Just do SIOCLIFREMOVEIF on loopback interfaces */ 939 bzero(&lifr, sizeof (lifr)); 940 if (i_ipadm_is_loopback(ifname) || 941 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) { 942 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 943 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6, 944 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 945 return (ipadm_errno2status(errno)); 946 } 947 return (IPADM_SUCCESS); 948 } 949 950 /* 951 * We used /dev/udp or udp6 to set up the mux. So we have to use 952 * the same now for PUNLINK also. 953 */ 954 if (v6) { 955 udp_dev_name = UDP6_DEV_NAME; 956 sock = iph->iph_sock6; 957 } else { 958 udp_dev_name = UDP_DEV_NAME; 959 sock = iph->iph_sock; 960 } 961 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) { 962 ret = ipadm_errno2status(errno); 963 goto done; 964 } 965 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd); 966 if (ret != IPADM_SUCCESS) 967 goto done; 968 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 969 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 970 ret = ipadm_errno2status(errno); 971 goto done; 972 } 973 flags = lifr.lifr_flags; 974 again: 975 if (flags & IFF_IPMP) { 976 /* 977 * There are two reasons the I_PUNLINK can fail with EBUSY: 978 * (1) if IP interfaces are in the group, or (2) if IPMP data 979 * addresses are administratively up. For case (1), we fail 980 * here with a specific error message. For case (2), we bring 981 * down the addresses prior to doing the I_PUNLINK. If the 982 * I_PUNLINK still fails with EBUSY then the configuration 983 * must have changed after our checks, in which case we branch 984 * back up to `again' and rerun this logic. The net effect is 985 * that unplumbing an IPMP interface will only fail with EBUSY 986 * if IP interfaces are in the group. 987 */ 988 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) { 989 ret = ipadm_errno2status(errno); 990 goto done; 991 } 992 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, 993 LIFGRNAMSIZ); 994 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) { 995 ret = ipadm_errno2status(errno); 996 goto done; 997 } 998 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) { 999 ret = IPADM_GRP_NOTEMPTY; 1000 goto done; 1001 } 1002 1003 /* 1004 * The kernel will fail the I_PUNLINK if the IPMP interface 1005 * has administratively up addresses; bring them down. 1006 */ 1007 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE, 1008 0, &ifaddrs) == -1) { 1009 ret = ipadm_errno2status(errno); 1010 goto done; 1011 } 1012 ifaddrp = ifaddrs; 1013 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) { 1014 int sock = (ifaddrp->ia_flags & IFF_IPV4) ? 1015 iph->iph_sock : iph->iph_sock6; 1016 struct lifreq lifrl; 1017 1018 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) || 1019 (!(ifaddrp->ia_flags & IFF_IPV6) && v6)) 1020 continue; 1021 1022 bzero(&lifrl, sizeof (lifrl)); 1023 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name, 1024 sizeof (lifrl.lifr_name)); 1025 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) { 1026 ret = ipadm_errno2status(errno); 1027 ifaddrlistx_free(ifaddrs); 1028 goto done; 1029 } 1030 if (lifrl.lifr_flags & IFF_UP) { 1031 ret = i_ipadm_set_flags(iph, lifrl.lifr_name, 1032 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET : 1033 AF_INET6), 0, IFF_UP); 1034 if (ret != IPADM_SUCCESS) { 1035 ifaddrlistx_free(ifaddrs); 1036 goto done; 1037 } 1038 } else if (lifrl.lifr_flags & IFF_DUPLICATE) { 1039 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 || 1040 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) { 1041 ret = ipadm_errno2status(errno); 1042 ifaddrlistx_free(ifaddrs); 1043 goto done; 1044 } 1045 } 1046 } 1047 ifaddrlistx_free(ifaddrs); 1048 } 1049 1050 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 1051 ret = ipadm_errno2status(errno); 1052 goto done; 1053 } 1054 arp_muxid = lifr.lifr_arp_muxid; 1055 ip_muxid = lifr.lifr_ip_muxid; 1056 1057 /* 1058 * We don't have a good way of knowing whether the arp stream is 1059 * plumbed. We can't rely on IFF_NOARP because someone could 1060 * have turned it off later using "ifconfig xxx -arp". 1061 */ 1062 if (arp_muxid != 0) { 1063 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 1064 /* 1065 * See the comment before the SIOCGLIFGROUPNAME call. 1066 */ 1067 if (errno == EBUSY && (flags & IFF_IPMP)) 1068 goto again; 1069 1070 if ((errno == EINVAL) && 1071 (flags & (IFF_NOARP | IFF_IPV6))) { 1072 /* 1073 * Some plumbing utilities set the muxid to 1074 * -1 or some invalid value to signify that 1075 * there is no arp stream. Set the muxid to 0 1076 * before trying to unplumb the IP stream. 1077 * IP does not allow the IP stream to be 1078 * unplumbed if it sees a non-null arp muxid, 1079 * for consistency of IP-ARP streams. 1080 */ 1081 lifr.lifr_arp_muxid = 0; 1082 (void) ioctl(muxid_fd, SIOCSLIFMUXID, 1083 (caddr_t)&lifr); 1084 changed_arp_muxid = B_TRUE; 1085 } 1086 /* 1087 * In case of any other error, we continue with 1088 * the unplumb. 1089 */ 1090 } 1091 } 1092 1093 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 1094 if (changed_arp_muxid) { 1095 /* 1096 * Some error occurred, and we need to restore 1097 * everything back to what it was. 1098 */ 1099 save_errno = errno; 1100 lifr.lifr_arp_muxid = arp_muxid; 1101 lifr.lifr_ip_muxid = ip_muxid; 1102 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 1103 errno = save_errno; 1104 } 1105 /* 1106 * See the comment before the SIOCGLIFGROUPNAME call. 1107 */ 1108 if (errno == EBUSY && (flags & IFF_IPMP)) 1109 goto again; 1110 1111 ret = ipadm_errno2status(errno); 1112 } 1113 done: 1114 if (muxid_fd != -1) 1115 (void) close(muxid_fd); 1116 if (mux_fd != -1) 1117 (void) close(mux_fd); 1118 1119 if (af == AF_INET6 && ret == IPADM_SUCCESS) { 1120 /* 1121 * in.ndpd maintains the phyints in its memory even after 1122 * the interface is plumbed, so that it can be reused when 1123 * the interface gets plumbed again. The default behavior 1124 * of in.ndpd is to start autoconfiguration for an interface 1125 * that gets plumbed. We need to send the 1126 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this 1127 * default behavior on replumb. 1128 */ 1129 (void) i_ipadm_enable_autoconf(ifname); 1130 } 1131 return (ret); 1132 } 1133 1134 /* 1135 * Saves the given interface name `ifname' with address family `af' in 1136 * persistent DB. 1137 */ 1138 static ipadm_status_t 1139 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af) 1140 { 1141 ipmgmt_if_arg_t ifarg; 1142 int err; 1143 1144 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname)); 1145 ifarg.ia_family = af; 1146 ifarg.ia_cmd = IPMGMT_CMD_SETIF; 1147 ifarg.ia_flags = IPMGMT_PERSIST; 1148 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1149 return (ipadm_errno2status(err)); 1150 } 1151 1152 /* 1153 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST 1154 * is set in `ipadm_flags', it is also removed from persistent configuration. 1155 */ 1156 ipadm_status_t 1157 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1158 uint32_t ipadm_flags) 1159 { 1160 ipadm_status_t ret = IPADM_SUCCESS; 1161 ipadm_status_t db_status; 1162 char tmp_ifname[LIFNAMSIZ]; 1163 char *cp; 1164 struct ipadm_addrobj_s ipaddr; 1165 boolean_t is_persistent = 1166 (ipadm_flags & IPADM_OPT_PERSIST); 1167 1168 ret = i_ipadm_unplumb_if(iph, ifname, af); 1169 if (ret != IPADM_SUCCESS) 1170 goto done; 1171 1172 cp = strrchr(ifname, IPADM_LOGICAL_SEP); 1173 if (cp != NULL) { 1174 assert(iph->iph_flags & IPH_LEGACY); 1175 /* 1176 * This is a non-zero logical interface. 1177 * Find the addrobj and remove it from the daemon's memory. 1178 */ 1179 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname)); 1180 tmp_ifname[cp - ifname] = '\0'; 1181 *cp++ = '\0'; 1182 ipaddr.ipadm_lifnum = atoi(cp); 1183 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname, 1184 sizeof (ipaddr.ipadm_ifname)); 1185 ipaddr.ipadm_af = af; 1186 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr); 1187 if (ret == IPADM_SUCCESS) { 1188 ret = i_ipadm_delete_addrobj(iph, &ipaddr, 1189 IPADM_OPT_ACTIVE); 1190 } else if (ret == IPADM_NOTFOUND) { 1191 ret = IPADM_SUCCESS; 1192 } 1193 return (ret); 1194 } 1195 done: 1196 /* 1197 * Even if interface does not exist, remove all its addresses and 1198 * properties from the persistent store. If interface does not 1199 * exist both in kernel and the persistent store, return IPADM_ENXIO. 1200 */ 1201 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) { 1202 db_status = i_ipadm_delete_ifobj(iph, ifname, af, 1203 is_persistent); 1204 if (db_status == IPADM_SUCCESS) 1205 ret = IPADM_SUCCESS; 1206 } 1207 1208 return (ret); 1209 } 1210 1211 /* 1212 * Resets all addresses on interface `ifname' with address family `af' 1213 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties 1214 * and address objects of `ifname' for `af' are also removed from the 1215 * persistent DB. 1216 */ 1217 ipadm_status_t 1218 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1219 boolean_t is_persistent) 1220 { 1221 ipmgmt_if_arg_t ifarg; 1222 int err; 1223 1224 ifarg.ia_cmd = IPMGMT_CMD_RESETIF; 1225 ifarg.ia_flags = IPMGMT_ACTIVE; 1226 if (is_persistent) 1227 ifarg.ia_flags |= IPMGMT_PERSIST; 1228 ifarg.ia_family = af; 1229 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ); 1230 1231 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE); 1232 return (ipadm_errno2status(err)); 1233 } 1234 1235 /* 1236 * Create the interface by plumbing it for IP. 1237 * This function will check if there is saved configuration information 1238 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space 1239 * for `ifname' is taken. 1240 */ 1241 ipadm_status_t 1242 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1243 uint32_t ipadm_flags) 1244 { 1245 ipadm_status_t status; 1246 boolean_t p_exists; 1247 sa_family_t other_af; 1248 1249 /* 1250 * Return error, if the interface already exists in either the active 1251 * or the persistent configuration. 1252 */ 1253 if (ipadm_if_enabled(iph, ifname, af)) 1254 return (IPADM_IF_EXISTS); 1255 1256 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 1257 if (status != IPADM_SUCCESS) 1258 return (status); 1259 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 1260 if (p_exists) { 1261 if (!ipadm_if_enabled(iph, ifname, other_af)) 1262 return (IPADM_OP_DISABLE_OBJ); 1263 else 1264 ipadm_flags &= ~IPADM_OPT_PERSIST; 1265 } 1266 1267 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags)); 1268 } 1269 1270 /* 1271 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by 1272 * default, unless a value in `af' is specified. The interface may be plumbed 1273 * only if there is no previously saved persistent configuration information 1274 * for the interface (in which case the ipadm_enable_if() function must 1275 * be used to enable the interface). 1276 * 1277 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS, 1278 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE, 1279 * or appropriate ipadm_status_t corresponding to the errno. 1280 * 1281 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may 1282 * be over-written with the actual interface name when a PPA has to be 1283 * internally generated by the library. 1284 */ 1285 ipadm_status_t 1286 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af, 1287 uint32_t flags) 1288 { 1289 ipadm_status_t status; 1290 boolean_t created_v4 = B_FALSE; 1291 char newifname[LIFNAMSIZ]; 1292 1293 /* Check for the required authorization */ 1294 if (!ipadm_check_auth()) 1295 return (IPADM_EAUTH); 1296 1297 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 1298 !(flags & IPADM_OPT_ACTIVE)) || 1299 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP | 1300 IPADM_OPT_GENPPA))) { 1301 return (IPADM_INVALID_ARG); 1302 } 1303 if (flags & IPADM_OPT_GENPPA) { 1304 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >= 1305 LIFNAMSIZ) 1306 return (IPADM_INVALID_ARG); 1307 } else { 1308 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ) 1309 return (IPADM_INVALID_ARG); 1310 } 1311 1312 if (!i_ipadm_validate_ifname(iph, newifname)) 1313 return (IPADM_INVALID_ARG); 1314 1315 if ((af == AF_INET || af == AF_UNSPEC) && 1316 !i_ipadm_is_6to4(iph, ifname)) { 1317 status = i_ipadm_create_if(iph, ifname, AF_INET, flags); 1318 if (status != IPADM_SUCCESS) 1319 return (status); 1320 created_v4 = B_TRUE; 1321 } 1322 if (af == AF_INET6 || af == AF_UNSPEC) { 1323 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags); 1324 if (status != IPADM_SUCCESS) { 1325 if (created_v4) { 1326 (void) i_ipadm_delete_if(iph, ifname, AF_INET, 1327 IPADM_OPT_ACTIVE); 1328 } 1329 return (status); 1330 } 1331 } 1332 1333 return (IPADM_SUCCESS); 1334 } 1335 1336 /* 1337 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces 1338 * when `af' = AF_UNSPEC. 1339 */ 1340 ipadm_status_t 1341 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af, 1342 uint32_t flags) 1343 { 1344 ipadm_status_t status1 = IPADM_SUCCESS; 1345 ipadm_status_t status2 = IPADM_SUCCESS; 1346 ipadm_status_t other; 1347 1348 /* Check for the required authorization */ 1349 if (!ipadm_check_auth()) 1350 return (IPADM_EAUTH); 1351 1352 /* Validate the `ifname' for any logical interface. */ 1353 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) || 1354 !i_ipadm_validate_ifname(iph, ifname)) 1355 return (IPADM_INVALID_ARG); 1356 1357 if (af == AF_INET || af == AF_UNSPEC) 1358 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags); 1359 if (af == AF_INET6 || af == AF_UNSPEC) 1360 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags); 1361 /* 1362 * If the family has been uniquely identified, we return the 1363 * associated status, even if that is ENXIO. Calls from ifconfig 1364 * which can only unplumb one of IPv4/IPv6 at any time fall under 1365 * this category. 1366 */ 1367 if (af == AF_INET) 1368 return (status1); 1369 else if (af == AF_INET6) 1370 return (status2); 1371 else if (af != AF_UNSPEC) 1372 return (IPADM_INVALID_ARG); 1373 1374 /* 1375 * If af is AF_UNSPEC, then we return the following: 1376 * status1, if status1 == status2 1377 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS 1378 * and the other status is ENXIO 1379 * IPADM_ENXIO, if both status1 and status2 are ENXIO 1380 * IPADM_FAILURE otherwise. 1381 */ 1382 if (status1 == status2) { 1383 /* covers the case when both status1 and status2 are ENXIO */ 1384 return (status1); 1385 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1386 if (status1 == IPADM_SUCCESS) 1387 other = status2; 1388 else 1389 other = status1; 1390 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1391 } else { 1392 return (IPADM_FAILURE); 1393 } 1394 } 1395 1396 /* 1397 * Returns information about all interfaces in both active and persistent 1398 * configuration. If `ifname' is not NULL, it returns only the interface 1399 * identified by `ifname'. 1400 * 1401 * Return values: 1402 * On success: IPADM_SUCCESS. 1403 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE. 1404 */ 1405 ipadm_status_t 1406 ipadm_if_info(ipadm_handle_t iph, const char *ifname, 1407 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags) 1408 { 1409 ipadm_status_t status; 1410 ifspec_t ifsp; 1411 1412 if (if_info == NULL || iph == NULL || flags != 0) 1413 return (IPADM_INVALID_ARG); 1414 1415 if (ifname != NULL && 1416 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 1417 return (IPADM_INVALID_ARG); 1418 } 1419 1420 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags); 1421 if (status != IPADM_SUCCESS) 1422 return (status); 1423 if (ifname != NULL && *if_info == NULL) 1424 return (IPADM_ENXIO); 1425 1426 return (IPADM_SUCCESS); 1427 } 1428 1429 /* 1430 * Frees the linked list allocated by ipadm_if_info(). 1431 */ 1432 void 1433 ipadm_free_if_info(ipadm_if_info_t *ifinfo) 1434 { 1435 ipadm_if_info_t *ifinfo_next; 1436 1437 for (; ifinfo != NULL; ifinfo = ifinfo_next) { 1438 ifinfo_next = ifinfo->ifi_next; 1439 free(ifinfo); 1440 } 1441 } 1442 1443 /* 1444 * Re-enable the interface `ifname' based on the saved configuration 1445 * for `ifname'. 1446 */ 1447 ipadm_status_t 1448 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1449 { 1450 nvlist_t *ifnvl; 1451 ipadm_status_t status; 1452 ifspec_t ifsp; 1453 1454 /* Check for the required authorization */ 1455 if (!ipadm_check_auth()) 1456 return (IPADM_EAUTH); 1457 1458 /* Check for logical interfaces. */ 1459 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1460 return (IPADM_INVALID_ARG); 1461 1462 /* Enabling an interface persistently is not supported. */ 1463 if (flags & IPADM_OPT_PERSIST) 1464 return (IPADM_NOTSUP); 1465 1466 /* 1467 * Return early by checking if the interface is already enabled. 1468 */ 1469 if (ipadm_if_enabled(iph, ifname, AF_INET) && 1470 ipadm_if_enabled(iph, ifname, AF_INET6)) { 1471 return (IPADM_IF_EXISTS); 1472 } 1473 /* 1474 * Enable the interface and restore all its interface properties 1475 * and address objects. 1476 */ 1477 status = i_ipadm_init_ifs(iph, ifname, &ifnvl); 1478 if (status != IPADM_SUCCESS) 1479 return (status); 1480 1481 assert(ifnvl != NULL); 1482 /* 1483 * ipadm_enable_if() does exactly what ipadm_init_ifs() does, 1484 * but only for one interface. We need to set IPH_INIT because 1485 * ipmgmtd daemon does not have to write the interface to persistent 1486 * db. The interface is already available in persistent db 1487 * and we are here to re-enable the persistent configuration. 1488 */ 1489 iph->iph_flags |= IPH_INIT; 1490 status = i_ipadm_init_ifobj(iph, ifname, ifnvl); 1491 iph->iph_flags &= ~IPH_INIT; 1492 return (status); 1493 } 1494 1495 /* 1496 * Disable the interface `ifname' by removing it from the active configuration. 1497 * Error code return values follow the model in ipadm_delete_if() 1498 */ 1499 ipadm_status_t 1500 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags) 1501 { 1502 ipadm_status_t status1, status2, other; 1503 ifspec_t ifsp; 1504 1505 /* Check for the required authorization */ 1506 if (!ipadm_check_auth()) 1507 return (IPADM_EAUTH); 1508 1509 /* Check for logical interfaces. */ 1510 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid) 1511 return (IPADM_INVALID_ARG); 1512 1513 /* Disabling an interface persistently is not supported. */ 1514 if (flags & IPADM_OPT_PERSIST) 1515 return (IPADM_NOTSUP); 1516 1517 status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6); 1518 if (status1 == IPADM_SUCCESS) 1519 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE); 1520 status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET); 1521 if (status2 == IPADM_SUCCESS) 1522 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE); 1523 if (status1 == status2) { 1524 return (status2); 1525 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) { 1526 if (status1 == IPADM_SUCCESS) 1527 other = status2; 1528 else 1529 other = status1; 1530 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE); 1531 } else { 1532 return (IPADM_FAILURE); 1533 } 1534 } 1535