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