4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Argo Technologie SA.
  25  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  26  */
  27 
  28 /*
  29  * Contains DB walker functions, which are of type `db_wfunc_t';
  30  *
  31  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  32  *                              size_t bufsize, int *errp);
  33  *
  34  * ipadm_rw_db() walks through the data store, one line at a time and calls
  35  * these call back functions with:
  36  *      `cbarg'  - callback argument
  37  *      `db_nvl' - representing a line from DB in nvlist_t form
  38  *      `buf'    - character buffer to hold modified line
  39  *      `bufsize'- size of the buffer
  40  *      `errp' - captures any error inside the walker function.
  41  *
  42  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  43  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
 
 
  62 /* SCF related property group names and property names */
  63 #define IPMGMTD_APP_PG          "ipmgmtd"
  64 #define IPMGMTD_PROP_FBD        "first_boot_done"
  65 #define IPMGMTD_PROP_DBVER      "datastore_version"
  66 #define IPMGMTD_TRUESTR         "true"
  67 
  68 #define ATYPE   "_atype"                /* name of the address type nvpair */
  69 #define FLAGS   "_flags"                /* name of the flags nvpair */
  70 
  71 /*
  72  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  73  * IPADM_ADDR_IPV6_ADDRCONF.
  74  */
  75 #define IPMGMT_ATYPE_V6ACONF    0x1
  76 
  77 extern pthread_rwlock_t ipmgmt_dbconf_lock;
  78 
  79 /* signifies whether volatile copy of data store is in use */
  80 static boolean_t ipmgmt_rdonly_root = B_FALSE;
  81 
  82 /*
  83  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
  84  * in private nvpairs `proto', `ifname' & `aobjname'.
  85  */
  86 static boolean_t
  87 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
  88     const char *aobjname)
  89 {
  90         char            *db_proto = NULL, *db_ifname = NULL;
  91         char            *db_aobjname = NULL;
  92         nvpair_t        *nvp;
  93         char            *name;
  94 
  95         /* walk through db_nvl and retrieve all its private nvpairs */
  96         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
  97             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
  98                 name = nvpair_name(nvp);
  99                 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 100                         (void) nvpair_value_string(nvp, &db_proto);
 101                 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 
 310         } else {
 311                 buf[0] = '\0';
 312         }
 313 
 314         /* stop the search */
 315         return (B_FALSE);
 316 }
 317 
 318 /*
 319  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
 320  * found, when one of the following occurs first.
 321  * - the input aobjname matches the db aobjname. Return the db address.
 322  * - the input interface matches the db interface. Return all the
 323  *   matching db lines with addresses.
 324  */
 325 /* ARGSUSED */
 326 boolean_t
 327 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 328     int *errp)
 329 {
 330         ipmgmt_getaddr_cbarg_t  *cbarg = arg;
 331         char            *db_aobjname = NULL;
 332         char            *db_ifname = NULL;
 333         nvlist_t        *db_addr = NULL;
 334         char            name[IPMGMT_STRSIZE];
 335         nvpair_t        *nvp;
 336         boolean_t       add_nvl = B_FALSE;
 337 
 338         /* Parse db nvlist */
 339         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 340             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 341                 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 342                         (void) nvpair_value_nvlist(nvp, &db_addr);
 343                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 344                         (void) nvpair_value_string(nvp, &db_ifname);
 345                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 346                         (void) nvpair_value_string(nvp, &db_aobjname);
 347         }
 348 
 349         if (db_aobjname == NULL) /* Not an address */
 350                 return (B_TRUE);
 
 536                     instrval);
 537                 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 538                         return (B_FALSE);
 539         } else {
 540                 /* case of in-line update of a db entry */
 541                 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 542                         return (B_FALSE);
 543         }
 544 
 545         (void) memset(buf, 0, buflen);
 546         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 547                 /* buffer overflow */
 548                 *errp = ENOBUFS;
 549         }
 550 
 551         /* we updated the DB entry, so do not continue */
 552         return (B_FALSE);
 553 }
 554 
 555 /*
 556  * For the given `cbarg->cb_ifname' interface, retrieves any persistent
 557  * interface information (used in 'ipadm show-if')
 558  */
 559 /* ARGSUSED */
 560 boolean_t
 561 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 562     int *errp)
 563 {
 564         ipmgmt_getif_cbarg_t    *cbarg = arg;
 565         char                    *ifname = cbarg->cb_ifname;
 566         char                    *intf = NULL;
 567         ipadm_if_info_t         *ifp = NULL;
 568         sa_family_t             af;
 569         char                    *afstr;
 570 
 571         *errp = 0;
 572         if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) != 0 ||
 573             nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &intf) != 0 ||
 574             (ifname[0] != '\0' && strcmp(ifname, intf) != 0)) {
 575                 return (B_TRUE);
 576         }
 577         af = atoi(afstr);
 578         for (ifp = cbarg->cb_ifinfo; ifp != NULL; ifp = ifp->ifi_next) {
 579                 if (strcmp(ifp->ifi_name, intf) == 0)
 580                         break;
 581         }
 582         if (ifp == NULL) {
 583                 ipadm_if_info_t *new;
 584 
 585                 if ((new = calloc(1, sizeof (*new))) == NULL) {
 586                         *errp = ENOMEM;
 587                         return (B_FALSE); /* don't continue the walk */
 588                 }
 589                 new->ifi_next = cbarg->cb_ifinfo;
 590                 cbarg->cb_ifinfo = new;
 591                 ifp = new;
 592                 (void) strlcpy(ifp->ifi_name, intf, sizeof (ifp->ifi_name));
 593         }
 594 
 595         if (af == AF_INET) {
 596                 ifp->ifi_pflags |= IFIF_IPV4;
 597         } else {
 598                 assert(af == AF_INET6);
 599                 ifp->ifi_pflags |= IFIF_IPV6;
 600         }
 601 
 602         /* Terminate the walk if we found both v4 and v6 interfaces. */
 603         if (ifname[0] != '\0' && (ifp->ifi_pflags & IFIF_IPV4) &&
 604             (ifp->ifi_pflags & IFIF_IPV6))
 605                 return (B_FALSE);
 606 
 607         return (B_TRUE);
 608 }
 609 
 610 /*
 611  * Deletes those entries from the database for which interface name
 612  * matches with the given `cbarg->cb_ifname'
 613  */
 614 /* ARGSUSED */
 615 boolean_t
 616 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 617     int *errp)
 618 {
 619         ipmgmt_if_cbarg_t *cbarg = arg;
 620         boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 621         char            *ifname = cbarg->cb_ifname;
 622         char            *modstr = NULL;
 623         char            *afstr;
 624         char            *aobjname;
 625         uint_t          proto;
 626         ipmgmt_aobjmap_t *head;
 627         boolean_t       aobjfound = B_FALSE;
 628 
 629         *errp = 0;
 630 
 631         if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 632                 return (B_TRUE);
 633 
 634         if (nvlist_lookup_string(db_nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
 635                 if (atoi(afstr) == cbarg->cb_family)
 636                         goto delete;
 637                 return (B_TRUE);
 638         }
 639 
 640         /* Reset all the interface configurations for 'ifname' */
 641         if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 642             nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 643                 goto delete;
 644         }
 645         if (!isv6 &&
 646             (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 647             nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 648                 goto delete;
 649         }
 650 
 651         if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 652                 /*
 653                  * This must be an address property. Delete this
 654                  * line if there is a match in the address family.
 655                  */
 656                 head = aobjmap.aobjmap_head;
 
 672         }
 673 
 674         /*
 675          * If we are removing both v4 and v6 interface, then we get rid of
 676          * all the properties for that interface. On the other hand, if we
 677          * are deleting only v4 instance of an interface, then we delete v4
 678          * properties only.
 679          */
 680         if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 681                 proto = ipadm_str2proto(modstr);
 682                 switch (proto) {
 683                 case MOD_PROTO_IPV6:
 684                         if (isv6)
 685                                 goto delete;
 686                         break;
 687                 case MOD_PROTO_IPV4:
 688                         if (!isv6)
 689                                 goto delete;
 690                         break;
 691                 case MOD_PROTO_IP:
 692                         /* this should never be the case, today */
 693                         assert(0);
 694                         break;
 695                 }
 696         }
 697         /* Not found a match yet. Continue processing the db */
 698         return (B_TRUE);
 699 delete:
 700         /* delete the line from the db */
 701         buf[0] = '\0';
 702         return (B_TRUE);
 703 }
 704 
 705 /*
 706  * Deletes those entries from the database for which address object name
 707  * matches with the given `cbarg->cb_aobjname'
 708  */
 709 /* ARGSUSED */
 710 boolean_t
 711 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 712     int *errp)
 713 {
 
 873                                 return (EEXIST);
 874                 }
 875                 nodep->am_nextnum = nextnum;
 876         }
 877         return (i_ipmgmt_add_amnode(nodep));
 878 }
 879 
 880 /*
 881  * Performs following operations on the global `aobjmap' linked list.
 882  * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
 883  * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
 884  * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
 885  * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
 886  */
 887 int
 888 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
 889 {
 890         ipmgmt_aobjmap_t        *head, *prev, *matched = NULL;
 891         boolean_t               update = B_TRUE;
 892         int                     err = 0;
 893         ipadm_db_op_t           db_op;
 894 
 895         (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
 896 
 897         head = aobjmap.aobjmap_head;
 898         switch (op) {
 899         case ADDROBJ_ADD:
 900                 /*
 901                  * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
 902                  * update, else add the new node.
 903                  */
 904                 for (; head != NULL; head = head->am_next) {
 905                         /*
 906                          * For IPv6, we need to distinguish between the
 907                          * linklocal and non-linklocal nodes
 908                          */
 909                         if (strcmp(head->am_aobjname,
 910                             nodep->am_aobjname) == 0 &&
 911                             (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
 912                             head->ipmgmt_am_linklocal ==
 913                             nodep->ipmgmt_am_linklocal))
 
1349         (void) memset(buf, 0, buflen);
1350         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1351                 /* buffer overflow */
1352                 *errp = ENOBUFS;
1353         }
1354         return (B_TRUE);
1355 }
1356 
1357 /*
1358  * Called during boot.
1359  *
1360  * Walk through the DB and apply all the global module properties. We plow
1361  * through the DB even if we fail to apply property.
1362  */
1363 /* ARGSUSED */
1364 static boolean_t
1365 ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1366     int *errp)
1367 {
1368         ipadm_handle_t  iph = cbarg;
1369         nvpair_t        *nvp, *pnvp;
1370         char            *strval = NULL, *name, *mod = NULL, *pname;
1371         char            tmpstr[IPMGMT_STRSIZE];
1372         uint_t          proto;
1373 
1374         /*
1375          * We could have used nvl_exists() directly, however we need several
1376          * calls to it and each call traverses the list. Since this codepath
1377          * is exercised during boot, let's traverse the list ourselves and do
1378          * the necessary checks.
1379          */
1380         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1381             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1382                 name = nvpair_name(nvp);
1383                 if (IPADM_PRIV_NVP(name)) {
1384                         if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1385                             strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1386                                 return (B_TRUE);
1387                         else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1388                             nvpair_value_string(nvp, &mod) != 0)
1389                                 return (B_TRUE);
1390                 } else {
1391                         /* possible a property */
1392                         pnvp = nvp;
1393                 }
1394         }
1395 
1396         /* if we are here than we found a global property */
1397         assert(mod != NULL);
1398         assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1399 
1400         proto = ipadm_str2proto(mod);
1401         name = nvpair_name(pnvp);
1402         if (nvpair_value_string(pnvp, &strval) == 0) {
1403                 if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1404                     strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1405                         /* private protocol property */
1406                         pname = &name[1];
1407                 } else if (ipadm_legacy2new_propname(name, tmpstr,
1408                     sizeof (tmpstr), &proto) == 0) {
1409                         pname = tmpstr;
1410                 } else {
1411                         pname = name;
1412                 }
1413                 if (ipadm_set_prop(iph, pname, strval, proto,
1414                     IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1415                         ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1416                             pname);
 
1565  * places it in `pval'.
1566  */
1567 static int
1568 ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1569     void *pval, scf_type_t ptype)
1570 {
1571         ssize_t         numvals;
1572         scf_simple_prop_t *prop;
1573 
1574         prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1575         numvals = scf_simple_prop_numvalues(prop);
1576         if (numvals <= 0)
1577                 goto ret;
1578         switch (ptype) {
1579         case SCF_TYPE_INTEGER:
1580                 *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1581                 break;
1582         case SCF_TYPE_ASTRING:
1583                 *(char **)pval = scf_simple_prop_next_astring(prop);
1584                 break;
1585         }
1586 ret:
1587         scf_simple_prop_free(prop);
1588         return (numvals);
1589 }
1590 
1591 /*
1592  * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1593  */
1594 static int
1595 ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1596     void *pval, scf_type_t ptype)
1597 {
1598         scf_error_t             err;
1599 
1600         if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1601                 ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1602                     scf_strerror(scf_error()));
1603                 return (-1);
1604         }
 
1687         /*
1688          * 'datastore_version' doesn't exist. Which means that we need to
1689          * upgrade the datastore. We will create 'datastore_version' and set
1690          * the version value to IPADM_DB_VERSION, after we upgrade the file.
1691          */
1692         return (bval);
1693 }
1694 
1695 /*
1696  * This is called after the successful upgrade of the local data-store. With
1697  * the data-store upgraded to recent version we don't have to do anything on
1698  * subsequent reboots.
1699  */
1700 void
1701 ipmgmt_update_dbver(scf_resources_t *res)
1702 {
1703         int64_t         version = IPADM_DB_VERSION;
1704 
1705         (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1706             IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1707 }
 | 
 
 
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2016 Nexenta Systems, Inc.
  25  * Copyright 2016 Argo Technologie SA.
  26  * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
  27  */
  28 
  29 /*
  30  * Contains DB walker functions, which are of type `db_wfunc_t';
  31  *
  32  * typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
  33  *                              size_t bufsize, int *errp);
  34  *
  35  * ipadm_rw_db() walks through the data store, one line at a time and calls
  36  * these call back functions with:
  37  *      `cbarg'  - callback argument
  38  *      `db_nvl' - representing a line from DB in nvlist_t form
  39  *      `buf'    - character buffer to hold modified line
  40  *      `bufsize'- size of the buffer
  41  *      `errp' - captures any error inside the walker function.
  42  *
  43  * All the 'write' callback functions modify `db_nvl' based on `cbarg' and
  44  * copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
 
 
  63 /* SCF related property group names and property names */
  64 #define IPMGMTD_APP_PG          "ipmgmtd"
  65 #define IPMGMTD_PROP_FBD        "first_boot_done"
  66 #define IPMGMTD_PROP_DBVER      "datastore_version"
  67 #define IPMGMTD_TRUESTR         "true"
  68 
  69 #define ATYPE   "_atype"                /* name of the address type nvpair */
  70 #define FLAGS   "_flags"                /* name of the flags nvpair */
  71 
  72 /*
  73  * flag used by ipmgmt_persist_aobjmap() to indicate address type is
  74  * IPADM_ADDR_IPV6_ADDRCONF.
  75  */
  76 #define IPMGMT_ATYPE_V6ACONF    0x1
  77 
  78 extern pthread_rwlock_t ipmgmt_dbconf_lock;
  79 
  80 /* signifies whether volatile copy of data store is in use */
  81 static boolean_t ipmgmt_rdonly_root = B_FALSE;
  82 
  83 typedef int ipmgmt_if_updater_func_t(nvlist_t *, nvpair_t *, uint_t);
  84 
  85 static ipmgmt_if_updater_func_t ipmgmt_if_family_updater;
  86 static ipmgmt_if_updater_func_t ipmgmt_if_groupmembers_updater;
  87 
  88 static int ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl);
  89 
  90 typedef struct {
  91         const char      *name;
  92         ipmgmt_if_updater_func_t        *func;
  93 } ipmgmt_if_updater_ent_t;
  94 
  95 static ipmgmt_if_updater_ent_t ipmgmt_if_updater_ent[] = {
  96         {IPADM_NVP_FAMILIES, ipmgmt_if_family_updater},
  97         {IPADM_NVP_MIFNAMES, ipmgmt_if_groupmembers_updater},
  98         {NULL, NULL}
  99 };
 100 
 101 static ipmgmt_if_updater_ent_t *
 102 ipmgmt_find_if_field_updater(const char *field_name)
 103 {
 104         int i;
 105 
 106         for (i = 0; ipmgmt_if_updater_ent[i].name != NULL; i++) {
 107                 if (strcmp(field_name, ipmgmt_if_updater_ent[i].name) == 0) {
 108                         break;
 109                 }
 110         }
 111 
 112         return (&ipmgmt_if_updater_ent[i]);
 113 }
 114 
 115 static int
 116 ipmgmt_if_groupmembers_updater(nvlist_t *db_nvl, nvpair_t *member_nvp,
 117     uint_t flags)
 118 {
 119         char    **members;
 120         char    *member;
 121         char    *out_members[256];
 122         uint_t  nelem = 0, cnt = 0;
 123         int     err;
 124 
 125         if ((err = nvpair_value_string(member_nvp, &member)) != 0)
 126                 return (err);
 127 
 128         err = nvlist_lookup_string_array(db_nvl, IPADM_NVP_MIFNAMES,
 129             &members, &nelem);
 130 
 131         if (err != 0 && (flags & IPMGMT_REMOVE))
 132                 return (ENOENT);
 133 
 134         while (nelem-- > 0) {
 135                 if ((flags & IPMGMT_REMOVE) &&
 136                     (strcmp(member, members[nelem]) == 0))
 137                         continue;
 138 
 139                 if ((out_members[cnt] = strdup(members[nelem])) == NULL) {
 140                         err = ENOMEM;
 141                         goto fail;
 142                 }
 143 
 144                 cnt++;
 145         }
 146 
 147         if (flags & IPMGMT_APPEND) {
 148                 if ((out_members[cnt] = strdup(member)) == NULL) {
 149                         err = ENOMEM;
 150                         goto fail;
 151                 }
 152                 cnt++;
 153         }
 154 
 155         if (cnt == 0) {
 156                 err = nvlist_remove(db_nvl, IPADM_NVP_MIFNAMES,
 157                     DATA_TYPE_STRING_ARRAY);
 158         } else {
 159                 err = nvlist_add_string_array(db_nvl, IPADM_NVP_MIFNAMES,
 160                     out_members, cnt);
 161         }
 162 
 163 fail:
 164         while (cnt--)
 165                 free(out_members[cnt]);
 166 
 167         return (err);
 168 }
 169 
 170 static int
 171 ipmgmt_if_family_updater(nvlist_t *db_nvl, nvpair_t *families_nvp, uint_t flags)
 172 {
 173         uint16_t *families;
 174         uint_t  nelem = 0;
 175         int     err;
 176 
 177         if ((err = nvpair_value_uint16_array(families_nvp, &families,
 178             &nelem)) != 0)
 179                 return (err);
 180 
 181         return (ipmgmt_update_family_nvp(db_nvl, families[0], flags));
 182 }
 183 
 184 int
 185 ipmgmt_update_family_nvp(nvlist_t *nvl, sa_family_t af, uint_t flags)
 186 {
 187         uint16_t        *families = NULL;
 188         uint16_t        out_families[2];
 189         uint_t  nelem = 0, cnt;
 190         int     err;
 191 
 192         err = nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
 193             &families, &nelem);
 194         if (err != 0 && (flags & IPMGMT_REMOVE)) {
 195                 return (ENOENT);
 196         }
 197 
 198         if (flags & IPMGMT_APPEND) {
 199                 if (families != NULL) {
 200                         if (nelem == 2 || families[0] == af) {
 201                                 return (EEXIST);
 202                         }
 203                         out_families[0] = families[0];
 204                         out_families[1] = af;
 205                         cnt = 2;
 206                 } else {
 207                         out_families[0] = af;
 208                         cnt = 1;
 209                 }
 210         } else {
 211                 assert(nelem == 1 || nelem == 2);
 212                 cnt = 0;
 213                 while (nelem-- > 0) {
 214                         if (families[nelem] != af) {
 215                                 out_families[cnt] = families[nelem];
 216                                 cnt++;
 217                         }
 218                 }
 219         }
 220 
 221         if (cnt != 0) {
 222                 return (nvlist_add_uint16_array(nvl, IPADM_NVP_FAMILIES,
 223                     out_families, cnt));
 224         }
 225         return (nvlist_remove(nvl, IPADM_NVP_FAMILIES, DATA_TYPE_UINT16_ARRAY));
 226 }
 227 
 228 /*
 229  * Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
 230  * in private nvpairs `proto', `ifname' & `aobjname'.
 231  */
 232 static boolean_t
 233 ipmgmt_nvlist_match(nvlist_t *db_nvl, const char *proto, const char *ifname,
 234     const char *aobjname)
 235 {
 236         char            *db_proto = NULL, *db_ifname = NULL;
 237         char            *db_aobjname = NULL;
 238         nvpair_t        *nvp;
 239         char            *name;
 240 
 241         /* walk through db_nvl and retrieve all its private nvpairs */
 242         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 243             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 244                 name = nvpair_name(nvp);
 245                 if (strcmp(IPADM_NVP_PROTONAME, name) == 0)
 246                         (void) nvpair_value_string(nvp, &db_proto);
 247                 else if (strcmp(IPADM_NVP_IFNAME, name) == 0)
 
 456         } else {
 457                 buf[0] = '\0';
 458         }
 459 
 460         /* stop the search */
 461         return (B_FALSE);
 462 }
 463 
 464 /*
 465  * Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
 466  * found, when one of the following occurs first.
 467  * - the input aobjname matches the db aobjname. Return the db address.
 468  * - the input interface matches the db interface. Return all the
 469  *   matching db lines with addresses.
 470  */
 471 /* ARGSUSED */
 472 boolean_t
 473 ipmgmt_db_getaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 474     int *errp)
 475 {
 476         ipmgmt_get_cbarg_t      *cbarg = arg;
 477         char            *db_aobjname = NULL;
 478         char            *db_ifname = NULL;
 479         nvlist_t        *db_addr = NULL;
 480         char            name[IPMGMT_STRSIZE];
 481         nvpair_t        *nvp;
 482         boolean_t       add_nvl = B_FALSE;
 483 
 484         /* Parse db nvlist */
 485         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 486             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 487                 if (nvpair_type(nvp) == DATA_TYPE_NVLIST)
 488                         (void) nvpair_value_nvlist(nvp, &db_addr);
 489                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0)
 490                         (void) nvpair_value_string(nvp, &db_ifname);
 491                 else if (strcmp(nvpair_name(nvp), IPADM_NVP_AOBJNAME) == 0)
 492                         (void) nvpair_value_string(nvp, &db_aobjname);
 493         }
 494 
 495         if (db_aobjname == NULL) /* Not an address */
 496                 return (B_TRUE);
 
 682                     instrval);
 683                 if ((*errp = nvlist_add_string(db_nvl, name, pval)) != 0)
 684                         return (B_FALSE);
 685         } else {
 686                 /* case of in-line update of a db entry */
 687                 if ((*errp = nvlist_add_string(db_nvl, name, instrval)) != 0)
 688                         return (B_FALSE);
 689         }
 690 
 691         (void) memset(buf, 0, buflen);
 692         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 693                 /* buffer overflow */
 694                 *errp = ENOBUFS;
 695         }
 696 
 697         /* we updated the DB entry, so do not continue */
 698         return (B_FALSE);
 699 }
 700 
 701 /*
 702  * This function is used to update a DB line that describes
 703  * an interface, its family and group interface
 704  *
 705  */
 706 boolean_t
 707 ipmgmt_db_update_if(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 708     int *errp)
 709 {
 710         ipadm_dbwrite_cbarg_t *cb = arg;
 711         ipmgmt_if_updater_ent_t *updater;
 712         nvlist_t        *in_nvl = cb->dbw_nvl;
 713         uint_t          flags = cb->dbw_flags;
 714         nvpair_t        *nvp;
 715         char            *name;
 716         char            *db_ifname;
 717         char            *gifname = NULL;
 718         char            *mifname = NULL;
 719 
 720         *errp = 0;
 721 
 722         /* Only one flag */
 723         if ((flags & (IPMGMT_APPEND | IPMGMT_REMOVE)) == 0 ||
 724             ((flags & IPMGMT_APPEND) && (flags & IPMGMT_REMOVE))) {
 725                 *errp = EINVAL;
 726                 return (B_FALSE);
 727         }
 728 
 729         if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES))
 730                 return (B_TRUE);
 731 
 732         if (nvlist_exists(db_nvl, IPADM_NVP_IFCLASS) &&
 733             nvlist_lookup_string(db_nvl, IPADM_NVP_IFNAME, &db_ifname) == 0 &&
 734             nvlist_lookup_string(in_nvl, IPADM_NVP_GIFNAME, &gifname) == 0 &&
 735             nvlist_lookup_string(in_nvl, IPADM_NVP_MIFNAMES, &mifname) == 0 &&
 736             strcmp(db_ifname, mifname) == 0) {
 737                 if (flags & IPMGMT_APPEND) {
 738                         if ((*errp = nvlist_add_string(db_nvl,
 739                             IPADM_NVP_GIFNAME, gifname)) != 0)
 740                                 return (B_FALSE);
 741                 } else {
 742                         if ((*errp = nvlist_remove(db_nvl, IPADM_NVP_GIFNAME,
 743                             DATA_TYPE_STRING)) != 0)
 744                                 return (B_FALSE);
 745                 }
 746                 cb->dbw_flags &= ~IPMGMT_UPDATE_IPMP;
 747                 goto done;
 748         }
 749 
 750         if (!ipmgmt_nvlist_intersects(db_nvl, in_nvl))
 751                 return (B_TRUE);
 752 
 753         for (nvp = nvlist_next_nvpair(in_nvl, NULL); nvp != NULL;
 754             nvp = nvlist_next_nvpair(in_nvl, nvp)) {
 755                 name = nvpair_name(nvp);
 756                 if (strcmp(name, IPADM_NVP_FAMILIES) != 0 &&
 757                     strcmp(name, IPADM_NVP_MIFNAMES) != 0)
 758                         continue;
 759 
 760                 updater = ipmgmt_find_if_field_updater(name);
 761                 assert(updater != NULL);
 762                 *errp = (*updater->func)(db_nvl, nvp, flags);
 763                 if (*errp != 0)
 764                         return (B_FALSE);
 765         }
 766 
 767         cb->dbw_flags &= ~IPMGMT_UPDATE_IF;
 768 
 769 done:
 770         (void) memset(buf, 0, buflen);
 771         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 772                 *errp = ENOBUFS;
 773                 return (B_FALSE);
 774         }
 775 
 776         /* we finished all operations, so do not continue */
 777         if ((cb->dbw_flags & (IPMGMT_UPDATE_IF | IPMGMT_UPDATE_IPMP)) == 0)
 778                 return (B_FALSE);
 779 
 780         return (B_TRUE);
 781 }
 782 
 783 /*
 784  * For the given `cbarg->cb_ifname' interface retrieves
 785  * the nvlist that represents the persistent interface information
 786  * The nvlist contains:
 787  *      IPADM_NVP_IFNAME
 788  *      IPADM_NVP_FAMILIES
 789  *      IPADM_NVP_IF_CLASS
 790  *
 791  * (used in 'ipadm show-if')
 792  */
 793 /* ARGSUSED */
 794 boolean_t
 795 ipmgmt_db_getif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 796     int *errp)
 797 {
 798         ipmgmt_get_cbarg_t *cbarg = arg;
 799         char            *ifname = cbarg->cb_ifname;
 800         nvpair_t        *nvp;
 801         char            *db_ifname = NULL;
 802         uint16_t        *db_families = NULL;
 803         uint_t          nelem = 0;
 804 
 805         /* Parse db nvlist */
 806         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
 807             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
 808                 if (strcmp(nvpair_name(nvp), IPADM_NVP_IFNAME) == 0) {
 809                         (void) nvpair_value_string(nvp, &db_ifname);
 810                 } else if (strcmp(nvpair_name(nvp), IPADM_NVP_FAMILIES) == 0) {
 811                         (void) nvpair_value_uint16_array(nvp,
 812                             &db_families, &nelem);
 813                 }
 814         }
 815 
 816         if (db_ifname == NULL || db_families == NULL)
 817                 return (B_TRUE);
 818 
 819         if (ifname != NULL && ifname[0] != '\0' &&
 820             strcmp(ifname, db_ifname) != 0)
 821                 return (B_TRUE);
 822 
 823         *errp = nvlist_add_nvlist(cbarg->cb_onvl, db_ifname, db_nvl);
 824         if (*errp == 0)
 825                 cbarg->cb_ocnt++;
 826 
 827         if (ifname != NULL && ifname[0] != '\0')
 828                 return (B_FALSE);
 829 
 830         return (B_TRUE);
 831 }
 832 
 833 /*
 834  * Deletes those entries from the database for which interface name
 835  * matches with the given `cbarg->cb_ifname'
 836  */
 837 /* ARGSUSED */
 838 boolean_t
 839 ipmgmt_db_resetif(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 840     int *errp)
 841 {
 842         ipmgmt_if_cbarg_t *cbarg = arg;
 843         boolean_t       isv6 = (cbarg->cb_family == AF_INET6);
 844         char            *ifname = cbarg->cb_ifname;
 845         char            *modstr = NULL;
 846         char            *aobjname;
 847         uint_t          proto;
 848         ipmgmt_aobjmap_t *head;
 849         boolean_t       aobjfound = B_FALSE;
 850 
 851         *errp = 0;
 852 
 853         if (!ipmgmt_nvlist_contains(db_nvl, NULL, ifname, NULL))
 854                 return (B_TRUE);
 855 
 856         if (nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
 857 
 858                 if ((*errp = ipmgmt_update_family_nvp(db_nvl, cbarg->cb_family,
 859                     IPMGMT_REMOVE)) != 0) {
 860                         return (B_FALSE);
 861                 }
 862 
 863                 if (cbarg->cb_family == AF_INET) {
 864                         cbarg->cb_ipv4exists = B_FALSE;
 865                 } else {
 866                         assert(cbarg->cb_family == AF_INET6);
 867                         cbarg->cb_ipv6exists = B_FALSE;
 868                 }
 869                 if (!nvlist_exists(db_nvl, IPADM_NVP_FAMILIES)) {
 870                         cbarg->cb_ipv4exists = B_FALSE;
 871                         cbarg->cb_ipv6exists = B_FALSE;
 872                         goto delete;
 873                 }
 874                 /* Otherwise need to reconstruct this string */
 875                 (void) memset(buf, 0, buflen);
 876                 if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
 877                         /* buffer overflow */
 878                         *errp = ENOBUFS;
 879                         return (B_FALSE);
 880                 }
 881                 return (B_TRUE);
 882         }
 883 
 884         /* Reset all the interface configurations for 'ifname' */
 885         if (isv6 && (nvlist_exists(db_nvl, IPADM_NVP_IPV6ADDR) ||
 886             nvlist_exists(db_nvl, IPADM_NVP_INTFID))) {
 887                 goto delete;
 888         }
 889         if (!isv6 &&
 890             (nvlist_exists(db_nvl, IPADM_NVP_IPV4ADDR) ||
 891             nvlist_exists(db_nvl, IPADM_NVP_DHCP))) {
 892                 goto delete;
 893         }
 894 
 895         if (nvlist_lookup_string(db_nvl, IPADM_NVP_AOBJNAME, &aobjname) == 0) {
 896                 /*
 897                  * This must be an address property. Delete this
 898                  * line if there is a match in the address family.
 899                  */
 900                 head = aobjmap.aobjmap_head;
 
 916         }
 917 
 918         /*
 919          * If we are removing both v4 and v6 interface, then we get rid of
 920          * all the properties for that interface. On the other hand, if we
 921          * are deleting only v4 instance of an interface, then we delete v4
 922          * properties only.
 923          */
 924         if (nvlist_lookup_string(db_nvl, IPADM_NVP_PROTONAME, &modstr) == 0) {
 925                 proto = ipadm_str2proto(modstr);
 926                 switch (proto) {
 927                 case MOD_PROTO_IPV6:
 928                         if (isv6)
 929                                 goto delete;
 930                         break;
 931                 case MOD_PROTO_IPV4:
 932                         if (!isv6)
 933                                 goto delete;
 934                         break;
 935                 case MOD_PROTO_IP:
 936                         if (!cbarg->cb_ipv4exists && !cbarg->cb_ipv6exists)
 937                                 goto delete;
 938                         break;
 939                 }
 940         }
 941         /* Not found a match yet. Continue processing the db */
 942         return (B_TRUE);
 943 delete:
 944         /* delete the line from the db */
 945         buf[0] = '\0';
 946         return (B_TRUE);
 947 }
 948 
 949 /*
 950  * Deletes those entries from the database for which address object name
 951  * matches with the given `cbarg->cb_aobjname'
 952  */
 953 /* ARGSUSED */
 954 boolean_t
 955 ipmgmt_db_resetaddr(void *arg, nvlist_t *db_nvl, char *buf, size_t buflen,
 956     int *errp)
 957 {
 
1117                                 return (EEXIST);
1118                 }
1119                 nodep->am_nextnum = nextnum;
1120         }
1121         return (i_ipmgmt_add_amnode(nodep));
1122 }
1123 
1124 /*
1125  * Performs following operations on the global `aobjmap' linked list.
1126  * (a) ADDROBJ_ADD: add or update address object in `aobjmap'
1127  * (b) ADDROBJ_DELETE: delete address object from `aobjmap'
1128  * (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
1129  * (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
1130  */
1131 int
1132 ipmgmt_aobjmap_op(ipmgmt_aobjmap_t *nodep, uint32_t op)
1133 {
1134         ipmgmt_aobjmap_t        *head, *prev, *matched = NULL;
1135         boolean_t               update = B_TRUE;
1136         int                     err = 0;
1137         ipadm_db_op_t           db_op = IPADM_DB_READ;
1138 
1139         (void) pthread_rwlock_wrlock(&aobjmap.aobjmap_rwlock);
1140 
1141         head = aobjmap.aobjmap_head;
1142         switch (op) {
1143         case ADDROBJ_ADD:
1144                 /*
1145                  * check for stub nodes (added by ADDROBJ_LOOKUPADD) and
1146                  * update, else add the new node.
1147                  */
1148                 for (; head != NULL; head = head->am_next) {
1149                         /*
1150                          * For IPv6, we need to distinguish between the
1151                          * linklocal and non-linklocal nodes
1152                          */
1153                         if (strcmp(head->am_aobjname,
1154                             nodep->am_aobjname) == 0 &&
1155                             (head->am_atype != IPADM_ADDR_IPV6_ADDRCONF ||
1156                             head->ipmgmt_am_linklocal ==
1157                             nodep->ipmgmt_am_linklocal))
 
1593         (void) memset(buf, 0, buflen);
1594         if (ipadm_nvlist2str(db_nvl, buf, buflen) == 0) {
1595                 /* buffer overflow */
1596                 *errp = ENOBUFS;
1597         }
1598         return (B_TRUE);
1599 }
1600 
1601 /*
1602  * Called during boot.
1603  *
1604  * Walk through the DB and apply all the global module properties. We plow
1605  * through the DB even if we fail to apply property.
1606  */
1607 /* ARGSUSED */
1608 static boolean_t
1609 ipmgmt_db_init(void *cbarg, nvlist_t *db_nvl, char *buf, size_t buflen,
1610     int *errp)
1611 {
1612         ipadm_handle_t  iph = cbarg;
1613         nvpair_t        *nvp, *pnvp = NULL;
1614         char            *strval = NULL, *name, *mod = NULL, *pname;
1615         char            tmpstr[IPMGMT_STRSIZE];
1616         uint_t          proto;
1617 
1618         /*
1619          * We could have used nvl_exists() directly, however we need several
1620          * calls to it and each call traverses the list. Since this codepath
1621          * is exercised during boot, let's traverse the list ourselves and do
1622          * the necessary checks.
1623          */
1624         for (nvp = nvlist_next_nvpair(db_nvl, NULL); nvp != NULL;
1625             nvp = nvlist_next_nvpair(db_nvl, nvp)) {
1626                 name = nvpair_name(nvp);
1627                 if (IPADM_PRIV_NVP(name)) {
1628                         if (strcmp(name, IPADM_NVP_IFNAME) == 0 ||
1629                             strcmp(name, IPADM_NVP_AOBJNAME) == 0)
1630                                 return (B_TRUE);
1631                         else if (strcmp(name, IPADM_NVP_PROTONAME) == 0 &&
1632                             nvpair_value_string(nvp, &mod) != 0)
1633                                 return (B_TRUE);
1634                 } else {
1635                         /* possible a property */
1636                         pnvp = nvp;
1637                 }
1638         }
1639 
1640         /* If we are here then we have found a global property */
1641         assert(mod != NULL);
1642         assert(nvpair_type(pnvp) == DATA_TYPE_STRING);
1643 
1644         proto = ipadm_str2proto(mod);
1645         name = nvpair_name(pnvp);
1646         if (nvpair_value_string(pnvp, &strval) == 0) {
1647                 if (strncmp(name, IPADM_PERSIST_PRIVPROP_PREFIX,
1648                     strlen(IPADM_PERSIST_PRIVPROP_PREFIX)) == 0) {
1649                         /* private protocol property */
1650                         pname = &name[1];
1651                 } else if (ipadm_legacy2new_propname(name, tmpstr,
1652                     sizeof (tmpstr), &proto) == 0) {
1653                         pname = tmpstr;
1654                 } else {
1655                         pname = name;
1656                 }
1657                 if (ipadm_set_prop(iph, pname, strval, proto,
1658                     IPADM_OPT_ACTIVE) != IPADM_SUCCESS) {
1659                         ipmgmt_log(LOG_WARNING, "Failed to reapply property %s",
1660                             pname);
 
1809  * places it in `pval'.
1810  */
1811 static int
1812 ipmgmt_get_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1813     void *pval, scf_type_t ptype)
1814 {
1815         ssize_t         numvals;
1816         scf_simple_prop_t *prop;
1817 
1818         prop = scf_simple_prop_get(res->sr_handle, IPMGMTD_FMRI, pgname, pname);
1819         numvals = scf_simple_prop_numvalues(prop);
1820         if (numvals <= 0)
1821                 goto ret;
1822         switch (ptype) {
1823         case SCF_TYPE_INTEGER:
1824                 *(int64_t **)pval = scf_simple_prop_next_integer(prop);
1825                 break;
1826         case SCF_TYPE_ASTRING:
1827                 *(char **)pval = scf_simple_prop_next_astring(prop);
1828                 break;
1829         default:
1830                 break;
1831         }
1832 ret:
1833         scf_simple_prop_free(prop);
1834         return (numvals);
1835 }
1836 
1837 /*
1838  * It stores the `pval' for given `pgname'/`pname' property group in SCF.
1839  */
1840 static int
1841 ipmgmt_set_scfprop(scf_resources_t *res, const char *pgname, const char *pname,
1842     void *pval, scf_type_t ptype)
1843 {
1844         scf_error_t             err;
1845 
1846         if ((res->sr_pg = scf_pg_create(res->sr_handle)) == NULL) {
1847                 ipmgmt_log(LOG_WARNING, "failed to create property group: %s",
1848                     scf_strerror(scf_error()));
1849                 return (-1);
1850         }
 
1933         /*
1934          * 'datastore_version' doesn't exist. Which means that we need to
1935          * upgrade the datastore. We will create 'datastore_version' and set
1936          * the version value to IPADM_DB_VERSION, after we upgrade the file.
1937          */
1938         return (bval);
1939 }
1940 
1941 /*
1942  * This is called after the successful upgrade of the local data-store. With
1943  * the data-store upgraded to recent version we don't have to do anything on
1944  * subsequent reboots.
1945  */
1946 void
1947 ipmgmt_update_dbver(scf_resources_t *res)
1948 {
1949         int64_t         version = IPADM_DB_VERSION;
1950 
1951         (void) ipmgmt_set_scfprop(res, IPMGMTD_APP_PG,
1952             IPMGMTD_PROP_DBVER, &version, SCF_TYPE_INTEGER);
1953 }
1954 
1955 /*
1956  * Return TRUE if `ifname' has persistent configuration for the `af' address
1957  * family in the datastore.
1958  * It is possible to call the function with af == AF_UNSPEC, so in this case
1959  * the function returns TRUE if either AF_INET or AF_INET6 interface exists
1960  */
1961 boolean_t
1962 ipmgmt_persist_if_exists(const char *ifname, sa_family_t af)
1963 {
1964         boolean_t exists = B_FALSE;
1965         nvlist_t    *if_info_nvl;
1966         uint16_t    *families = NULL;
1967         sa_family_t af_db;
1968         uint_t  nelem = 0;
1969 
1970         if (ipmgmt_get_ifinfo_nvl(ifname, &if_info_nvl) != 0)
1971                 goto done;
1972 
1973         if (nvlist_lookup_uint16_array(if_info_nvl, IPADM_NVP_FAMILIES,
1974             &families, &nelem) != 0)
1975                 goto done;
1976 
1977         while (nelem-- > 0) {
1978                 af_db = families[nelem];
1979                 if (af_db == af || (af == AF_UNSPEC &&
1980                     (af_db == AF_INET || af_db == AF_INET6))) {
1981                         exists = B_TRUE;
1982                         break;
1983                 }
1984         }
1985 
1986 done:
1987         if (if_info_nvl != NULL)
1988                 nvlist_free(if_info_nvl);
1989 
1990         return (exists);
1991 }
1992 
1993 /*
1994  * Retrieves the membership information for the requested mif_name
1995  * if mif_name is a memeber of a IPMP group, then gif_name will contain
1996  * the name of IPMP group interface, otherwise the variable will be empty
1997  */
1998 void
1999 ipmgmt_get_group_interface(const char *mif_name, char *gif_name, size_t size)
2000 {
2001         char    *gif_name_from_nvl;
2002         nvlist_t        *if_info_nvl;
2003 
2004         gif_name[0] = '\0';
2005 
2006         if (ipmgmt_get_ifinfo_nvl(mif_name, &if_info_nvl) != 0)
2007                 goto done;
2008 
2009         if (nvlist_lookup_string(if_info_nvl, IPADM_NVP_GIFNAME,
2010             &gif_name_from_nvl) != 0)
2011                 goto done;
2012 
2013         (void) strlcpy(gif_name, gif_name_from_nvl, size);
2014 
2015 done:
2016         if (if_info_nvl != NULL)
2017                 nvlist_free(if_info_nvl);
2018 }
2019 
2020 static int
2021 ipmgmt_get_ifinfo_nvl(const char *ifname, nvlist_t **if_info_nvl)
2022 {
2023         ipmgmt_get_cbarg_t cbarg;
2024         nvpair_t    *nvp;
2025         nvlist_t    *nvl;
2026         int     err;
2027 
2028         cbarg.cb_ifname = NULL;
2029         cbarg.cb_aobjname = NULL;
2030         cbarg.cb_ocnt = 0;
2031 
2032         if ((err = nvlist_alloc(&cbarg.cb_onvl, NV_UNIQUE_NAME, 0)) != 0)
2033                 goto done;
2034 
2035         err = ipmgmt_db_walk(ipmgmt_db_getif, &cbarg, IPADM_DB_READ);
2036         if (err == ENOENT && cbarg.cb_ocnt > 0)
2037                 err = 0;
2038 
2039         if (err != 0)
2040                 goto done;
2041 
2042         for (nvp = nvlist_next_nvpair(cbarg.cb_onvl, NULL); nvp != NULL;
2043             nvp = nvlist_next_nvpair(cbarg.cb_onvl, nvp)) {
2044 
2045                 if (strcmp(nvpair_name(nvp), ifname) != 0)
2046                         continue;
2047 
2048                 if ((err = nvpair_value_nvlist(nvp, &nvl)) != 0 ||
2049                     (err = nvlist_dup(nvl, if_info_nvl, NV_UNIQUE_NAME)) != 0)
2050                         *if_info_nvl = NULL;
2051 
2052                 break;
2053         }
2054 
2055 done:
2056         nvlist_free(cbarg.cb_onvl);
2057 
2058         return (err);
2059 }
 |