1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
  26  */
  27 
  28 #include <assert.h>
  29 #include <ctype.h>
  30 #include <libgen.h>
  31 #include <netdb.h>
  32 #include <sys/param.h>
  33 #include <sys/types.h>
  34 #include <sys/stat.h>
  35 #include <sys/socket.h>
  36 #include <netinet/in.h>
  37 #include <arpa/inet.h>
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <strings.h>
  41 #include <unistd.h>
  42 #include <libdladm.h>
  43 #include <libipadm.h>
  44 
  45 #include "libnwam_impl.h"
  46 #include <libnwam_priv.h>
  47 #include <libnwam.h>
  48 
  49 /*
  50  * Functions to support creating, modifying, destroying, querying the
  51  * state of and changing the state of NCP (Network Configuration Profiles)
  52  * and the NCUs (Network Configuration Units) that are contained in those
  53  * NCP objects.  An NCP is simply a container for a set of NCUs which represent
  54  * the datalink and interface configuration preferences for the system.
  55  * An NCP can consist a set of prioritized link NCUs, e.g. wired links preferred
  56  * over wireless, a set of manually enabled/diasbled NCUs, or a combination
  57  * of both. Interface NCUs inherit activation from their underlying links,
  58  * so if wired is preferred over wireless and a cable is plugged in,
  59  * the wired link NCU will be active, as will the IP interface NCU above it.
  60  */
  61 
  62 /*
  63  * The NCU property table is used to mapping property types to property name
  64  * strings, their associated value types etc. The table is used for validation
  65  * purposes, and for commit()ing and read()ing NCUs.
  66  */
  67 
  68 static nwam_error_t valid_type(nwam_value_t);
  69 static nwam_error_t valid_class(nwam_value_t);
  70 static nwam_error_t valid_ncp(nwam_value_t);
  71 static nwam_error_t valid_priority_mode(nwam_value_t);
  72 static nwam_error_t valid_ncu_activation_mode(nwam_value_t);
  73 static nwam_error_t valid_link_autopush(nwam_value_t);
  74 static nwam_error_t valid_link_mtu(nwam_value_t);
  75 static nwam_error_t valid_ip_version(nwam_value_t);
  76 static nwam_error_t valid_addrsrc_v4(nwam_value_t);
  77 static nwam_error_t valid_addrsrc_v6(nwam_value_t);
  78 static nwam_error_t valid_reqhost(nwam_value_t);
  79 
  80 struct nwam_prop_table_entry ncu_prop_table_entries[] = {
  81         {NWAM_NCU_PROP_TYPE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1, valid_type,
  82             "specifies the NCU type - valid values are \'datalink\' and \'ip\'",
  83             NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL},
  84         {NWAM_NCU_PROP_CLASS, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1,
  85             valid_class,
  86             "specifies the NCU class - valid values are "
  87             "\'phys\' and \'ip\'",
  88             NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL},
  89         {NWAM_NCU_PROP_PARENT_NCP, NWAM_VALUE_TYPE_STRING, B_FALSE, 1, 1,
  90             valid_ncp,
  91             "specifies the parent NCP name",
  92             NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL},
  93         {NWAM_NCU_PROP_ACTIVATION_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 1, 1,
  94             valid_ncu_activation_mode,
  95             "specifies the NCU activation mode - valid values are:\n"
  96             "\'prioritized\' and \'manual\'",
  97             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
  98         {NWAM_NCU_PROP_ENABLED, NWAM_VALUE_TYPE_BOOLEAN, B_TRUE, 0, 1,
  99             nwam_valid_boolean,
 100             "specifies if manual NCU is to be enabled",
 101             NWAM_FLAG_NCU_TYPE_ALL, NWAM_FLAG_NCU_CLASS_ALL},
 102         {NWAM_NCU_PROP_PRIORITY_GROUP, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1,
 103             nwam_valid_uint64,
 104             "specifies the priority grouping of NCUs - lower values are "
 105             "prioritized, negative values are invalid",
 106             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
 107         {NWAM_NCU_PROP_PRIORITY_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1,
 108             valid_priority_mode,
 109             "specifies the mode of prioritization - valid values are:\n"
 110             "\'exclusive\', \'shared\' and \'all\'",
 111             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
 112         {NWAM_NCU_PROP_LINK_MAC_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0, 1,
 113             nwam_valid_mac_addr,
 114             "specifies MAC address of form aa:bb:cc:dd:ee:ff for the link",
 115             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
 116         {NWAM_NCU_PROP_LINK_AUTOPUSH, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 117             NWAM_MAX_NUM_VALUES, valid_link_autopush,
 118             "specifies modules to autopush on link",
 119             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
 120         {NWAM_NCU_PROP_LINK_MTU, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0, 1,
 121             valid_link_mtu,
 122             "specifies MTU for link",
 123             NWAM_FLAG_NCU_TYPE_LINK, NWAM_FLAG_NCU_CLASS_ALL_LINK},
 124         {NWAM_NCU_PROP_IP_VERSION, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0,
 125             NWAM_MAX_NUM_VALUES, valid_ip_version,
 126             "specifies IP versions for IP NCU - valid values are:\n"
 127             "\'ipv4\' and \'ipv6\'",
 128             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 129         {NWAM_NCU_PROP_IPV4_ADDRSRC, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0,
 130             NWAM_MAX_NUM_VALUES, valid_addrsrc_v4,
 131             "specifies IPv4 address source(s) - valid values are:\n"
 132             "\'dhcp\' and \'static\'",
 133             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 134         {NWAM_NCU_PROP_IPV4_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 135             NWAM_MAX_NUM_VALUES, nwam_valid_host_v4,
 136             "specifies static IPv4 host address(es)",
 137             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 138         {NWAM_NCU_PROP_IPV4_DEFAULT_ROUTE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 139             1, nwam_valid_route_v4,
 140             "specifies per-interface default IPv4 route",
 141             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 142         {NWAM_NCU_PROP_IPV6_ADDRSRC, NWAM_VALUE_TYPE_UINT64, B_FALSE, 0,
 143             NWAM_MAX_NUM_VALUES, valid_addrsrc_v6,
 144             "specifies IPv6 address source(s) - valid values are:\n"
 145             "\'dhcp\', \'autoconf\' and \'static\'.\n"
 146             "\'dhcp\' and \'autoconf\' are mandatory values.",
 147             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 148         {NWAM_NCU_PROP_IPV6_ADDR, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 149             NWAM_MAX_NUM_VALUES, nwam_valid_host_v6,
 150             "specifies static IPv6 host address(es)",
 151             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 152         {NWAM_NCU_PROP_IPV6_DEFAULT_ROUTE, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 153             1, nwam_valid_route_v6,
 154             "specifies per-interface default IPv6 route",
 155             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 156         {NWAM_NCU_PROP_IP_PRIMARY, NWAM_VALUE_TYPE_BOOLEAN, B_FALSE, 0,
 157             1, nwam_valid_boolean,
 158             "specifies the status of an interface as primary for the delivery"
 159             " of client-wide configuration data",
 160             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 161         {NWAM_NCU_PROP_IP_REQHOST, NWAM_VALUE_TYPE_STRING, B_FALSE, 0,
 162             1, valid_reqhost,
 163             "specifies a requested hostname for the interface",
 164             NWAM_FLAG_NCU_TYPE_INTERFACE, NWAM_FLAG_NCU_CLASS_ALL_INTERFACE},
 165 };
 166 
 167 #define NWAM_NUM_NCU_PROPS      (sizeof (ncu_prop_table_entries) / \
 168                                 sizeof (*ncu_prop_table_entries))
 169 
 170 struct nwam_prop_table ncu_prop_table =
 171         { NWAM_NUM_NCU_PROPS, ncu_prop_table_entries };
 172 
 173 nwam_error_t
 174 nwam_ncp_get_name(nwam_ncp_handle_t ncph, char **namep)
 175 {
 176         return (nwam_get_name(ncph, namep));
 177 }
 178 
 179 static nwam_error_t
 180 nwam_ncp_name_to_file(const char *name, char **filename)
 181 {
 182         assert(name != NULL && filename != NULL);
 183 
 184         if ((*filename = malloc(MAXPATHLEN)) == NULL)
 185                 return (NWAM_NO_MEMORY);
 186 
 187         (void) snprintf(*filename, MAXPATHLEN, "%s%s%s%s", NWAM_CONF_DIR,
 188             NWAM_NCP_CONF_FILE_PRE, name, NWAM_NCP_CONF_FILE_SUF);
 189 
 190         return (NWAM_SUCCESS);
 191 }
 192 
 193 /* ARGSUSED1 */
 194 nwam_error_t
 195 nwam_ncp_create(const char *name, uint64_t flags, nwam_ncp_handle_t *ncphp)
 196 {
 197         nwam_error_t err;
 198         char *ncpfile;
 199 
 200         if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, name, ncphp))
 201             != NWAM_SUCCESS)
 202                 return (err);
 203 
 204         /* Create empty container for NCUs */
 205         if ((err = nwam_ncp_name_to_file(name, &ncpfile))
 206             != NWAM_SUCCESS) {
 207                 nwam_free(*ncphp);
 208                 *ncphp = NULL;
 209                 return (err);
 210         }
 211 
 212         if ((err = nwam_commit(ncpfile, *ncphp, flags)) != NWAM_SUCCESS) {
 213                 nwam_free(*ncphp);
 214                 *ncphp = NULL;
 215         }
 216 
 217         free(ncpfile);
 218 
 219         return (err);
 220 }
 221 
 222 /* Used by libnwam_files.c */
 223 nwam_error_t
 224 nwam_ncp_file_to_name(const char *path, char **name)
 225 {
 226         char path_copy[MAXPATHLEN];
 227         char *filename, *suffix;
 228 
 229         assert(path != NULL && name != NULL);
 230 
 231         /* Make a copy as basename(3c) may modify string */
 232         (void) strlcpy(path_copy, path, MAXPATHLEN);
 233 
 234         if ((*name = malloc(NWAM_MAX_NAME_LEN)) == NULL)
 235                 return (NWAM_NO_MEMORY);
 236 
 237         if ((filename = basename(path_copy)) == NULL) {
 238                 free(*name);
 239                 return (NWAM_ENTITY_INVALID);
 240         }
 241 
 242         /* Ensure filename begins/ends with right prefix/suffix */
 243         if (sscanf(filename, NWAM_NCP_CONF_FILE_PRE "%256[^\n]s", *name) < 1) {
 244                 free(*name);
 245                 return (NWAM_ENTITY_INVALID);
 246         }
 247         suffix = *name + strlen(*name) - strlen(NWAM_NCP_CONF_FILE_SUF);
 248         if (strstr(*name, NWAM_NCP_CONF_FILE_SUF) != suffix) {
 249                 free(*name);
 250                 return (NWAM_ENTITY_INVALID);
 251         }
 252         suffix[0] = '\0';
 253 
 254         return (NWAM_SUCCESS);
 255 }
 256 
 257 /* ARGSUSED1 */
 258 nwam_error_t
 259 nwam_ncp_read(const char *name, uint64_t flags, nwam_ncp_handle_t *ncphp)
 260 {
 261         char *filename;
 262         nwam_error_t err;
 263 
 264         assert(name != NULL && ncphp != NULL);
 265 
 266         /* try to read the associated ncp configuration */
 267         if ((err = nwam_ncp_name_to_file(name, &filename)) != NWAM_SUCCESS) {
 268                 *ncphp = NULL;
 269                 return (err);
 270         }
 271 
 272         err = nwam_read(NWAM_OBJECT_TYPE_NCP, filename, name, flags, ncphp);
 273         free(filename);
 274         return (err);
 275 }
 276 
 277 static nwam_error_t
 278 nwam_ncu_get_parent_ncp_name(nwam_ncu_handle_t ncuh, char **parentnamep)
 279 {
 280         nwam_value_t parentval = NULL;
 281         char *parentname;
 282         nwam_error_t err;
 283 
 284         if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_PARENT_NCP,
 285             &parentval)) != NWAM_SUCCESS ||
 286             (err = nwam_value_get_string(parentval, &parentname))
 287             != NWAM_SUCCESS ||
 288             (*parentnamep = strdup(parentname)) == NULL) {
 289                 if (parentval != NULL)
 290                         nwam_value_free(parentval);
 291                 *parentnamep = NULL;
 292                 return (err);
 293         }
 294         nwam_value_free(parentval);
 295 
 296         return (NWAM_SUCCESS);
 297 }
 298 
 299 static int
 300 nwam_ncp_copy_callback(nwam_ncu_handle_t oldncuh, void *arg)
 301 {
 302         nwam_error_t err;
 303         nwam_ncu_handle_t newncuh = NULL;
 304         char *oldparent;
 305         char *oldfilename = NULL, *newfilename = NULL;
 306         nwam_ncp_handle_t newncph = (nwam_ncp_handle_t)arg;
 307         nwam_value_t newparentval;
 308 
 309         /* Get filenames for the new and old NCU's */
 310         if ((err = nwam_ncu_get_parent_ncp_name(oldncuh, &oldparent))
 311             != NWAM_SUCCESS)
 312                 return (err);
 313         err = nwam_ncp_name_to_file(oldparent, &oldfilename);
 314         free(oldparent);
 315         if (err != NWAM_SUCCESS)
 316                 return (err);
 317         if ((err = nwam_ncp_name_to_file(newncph->nwh_name, &newfilename))
 318             != NWAM_SUCCESS)
 319                 goto fail;
 320 
 321         /* new NCU name (and typedname) is the same as the old name */
 322         if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, oldncuh->nwh_name,
 323             &newncuh)) != NWAM_SUCCESS)
 324                 goto fail;
 325         /* Duplicate the old NCU's data */
 326         if ((err = nwam_dup_object_list(oldncuh->nwh_data,
 327             &(newncuh->nwh_data))) != NWAM_SUCCESS)
 328                 goto fail;
 329 
 330         /* Update the parent property for the new NCU */
 331         if ((err = nwam_value_create_string(newncph->nwh_name, &newparentval))
 332             != NWAM_SUCCESS)
 333                 goto fail;
 334         err = nwam_set_prop_value(newncuh->nwh_data, NWAM_NCU_PROP_PARENT_NCP,
 335             newparentval);
 336         nwam_value_free(newparentval);
 337         if (err != NWAM_SUCCESS)
 338                 goto fail;
 339 
 340         /* Save the new NCU */
 341         err = nwam_commit(newfilename, newncuh, 0);
 342 
 343 fail:
 344         free(oldfilename);
 345         free(newfilename);
 346         nwam_ncu_free(newncuh);
 347         return (err);
 348 }
 349 
 350 nwam_error_t
 351 nwam_ncp_copy(nwam_ncp_handle_t oldncph, const char *newname,
 352     nwam_ncp_handle_t *newncphp)
 353 {
 354         nwam_ncp_handle_t ncph;
 355         nwam_error_t err;
 356         int cb_ret;
 357 
 358         assert(oldncph != NULL && newname != NULL && newncphp != NULL);
 359 
 360         /* check if newname NCP already exists */
 361         if (nwam_ncp_read(newname, 0,  &ncph) == NWAM_SUCCESS) {
 362                 nwam_ncp_free(ncph);
 363                 *newncphp = NULL;
 364                 return (NWAM_ENTITY_EXISTS);
 365         }
 366 
 367         /* create new handle */
 368         if ((err = nwam_ncp_create(newname, 0, newncphp)) != NWAM_SUCCESS)
 369                 return (err);
 370 
 371         err = nwam_ncp_walk_ncus(oldncph, nwam_ncp_copy_callback, *newncphp,
 372             NWAM_FLAG_NCU_TYPE_CLASS_ALL, &cb_ret);
 373         if (err != NWAM_SUCCESS) {
 374                 /* remove the NCP even if any NCU's had already been copied */
 375                 (void) nwam_ncp_destroy(*newncphp, 0);
 376                 *newncphp = NULL;
 377                 if (err == NWAM_WALK_HALTED)
 378                         return (cb_ret);
 379                 else
 380                         return (err);
 381         }
 382 
 383         return (NWAM_SUCCESS);
 384 }
 385 
 386 /*
 387  * Convert type to flag
 388  */
 389 static uint64_t
 390 nwam_ncu_type_to_flag(nwam_ncu_type_t type)
 391 {
 392         switch (type) {
 393         case NWAM_NCU_TYPE_LINK:
 394                 return (NWAM_FLAG_NCU_TYPE_LINK);
 395         case NWAM_NCU_TYPE_INTERFACE:
 396                 return (NWAM_FLAG_NCU_TYPE_INTERFACE);
 397         case NWAM_NCU_TYPE_ANY:
 398                 return (NWAM_FLAG_NCU_TYPE_ALL);
 399         default:
 400                 return (0);
 401         }
 402 }
 403 
 404 /*
 405  * Convert class to flag
 406  */
 407 uint64_t
 408 nwam_ncu_class_to_flag(nwam_ncu_class_t class)
 409 {
 410         switch (class) {
 411         case NWAM_NCU_CLASS_PHYS:
 412                 return (NWAM_FLAG_NCU_CLASS_PHYS);
 413         case NWAM_NCU_CLASS_IP:
 414                 return (NWAM_FLAG_NCU_CLASS_IP);
 415         case NWAM_NCU_CLASS_ANY:
 416                 return (NWAM_FLAG_NCU_CLASS_ALL);
 417         default:
 418                 return (0);
 419         }
 420 }
 421 
 422 /*
 423  * Infer NCU type from NCU class
 424  */
 425 nwam_ncu_type_t
 426 nwam_ncu_class_to_type(nwam_ncu_class_t class)
 427 {
 428         switch (class) {
 429         case NWAM_NCU_CLASS_PHYS:
 430                 return (NWAM_NCU_TYPE_LINK);
 431         case NWAM_NCU_CLASS_IP:
 432                 return (NWAM_NCU_TYPE_INTERFACE);
 433         case NWAM_NCU_CLASS_ANY:
 434                 return (NWAM_NCU_TYPE_ANY);
 435         default:
 436                 return (NWAM_NCU_TYPE_UNKNOWN);
 437         }
 438 }
 439 
 440 /*
 441  * Make ncp active, deactivating any other active ncp.
 442  */
 443 nwam_error_t
 444 nwam_ncp_enable(nwam_ncp_handle_t ncph)
 445 {
 446         nwam_error_t err;
 447         char *name;
 448 
 449         assert(ncph != NULL);
 450 
 451         err = nwam_enable(NULL, ncph);
 452 
 453         if (err == NWAM_ERROR_BIND) {
 454                 /*
 455                  * nwamd is not running, set active_ncp property so when
 456                  * nwamd is next started, this NCP will be used.
 457                  */
 458                 if ((err = nwam_ncp_get_name(ncph, &name)) != NWAM_SUCCESS)
 459                         return (err);
 460 
 461                 err = nwam_set_smf_string_property(NWAM_FMRI, NWAM_PG,
 462                     NWAM_PROP_ACTIVE_NCP, name);
 463                 free(name);
 464         }
 465 
 466         return (err);
 467 }
 468 
 469 /* Compare NCP names c1 and c2 using strcasecmp() */
 470 static int
 471 ncpname_cmp(const void *c1, const void *c2)
 472 {
 473         return (strcasecmp(*(const char **)c1, *(const char **)c2));
 474 }
 475 
 476 /* ARGSUSED1 */
 477 nwam_error_t
 478 nwam_walk_ncps(int (*cb)(nwam_ncp_handle_t, void *), void *data,
 479     uint64_t flags, int *retp)
 480 {
 481         char *ncpname, **ncpfiles;
 482         nwam_ncp_handle_t ncph;
 483         nwam_error_t err;
 484         nwam_value_t value;
 485         void *objlist;
 486         uint_t i, num_ncpfiles;
 487         int ret = 0;
 488 
 489         assert(cb != NULL);
 490 
 491         if ((err = nwam_valid_flags(flags, NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS)
 492                 return (err);
 493         /*
 494          * To get list of NCP files, call nwam_read_object_from_backend()
 495          * with "parent" argument set to NULL. We get back an object list
 496          * consisting of string arrays for each object type - NCP, ENM
 497          * and location. We retrieve the NCP list, which corresponds to
 498          * the set of NCP backend parent objects (these are files at present).
 499          */
 500         if ((err = nwam_read_object_from_backend(NULL, NULL, flags,
 501             &objlist)) != NWAM_SUCCESS)
 502                 return (err);
 503 
 504         if ((err = nwam_get_prop_value(objlist, NWAM_NCP_OBJECT_STRING, &value))
 505             != NWAM_SUCCESS) {
 506                 nwam_free_object_list(objlist);
 507                 return (err);
 508         }
 509         if ((err = nwam_value_get_string_array(value, &ncpfiles,
 510             &num_ncpfiles)) != NWAM_SUCCESS) {
 511                 nwam_value_free(value);
 512                 nwam_free_object_list(objlist);
 513                 return (err);
 514         }
 515 
 516         /* sort the NCP names alphabetically */
 517         qsort(ncpfiles, num_ncpfiles, sizeof (char *), ncpname_cmp);
 518 
 519         for (i = 0; i < num_ncpfiles; i++) {
 520                 if (nwam_ncp_file_to_name(ncpfiles[i], &ncpname)
 521                     != NWAM_SUCCESS)
 522                         continue;
 523                 if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, ncpname,
 524                     &ncph)) != NWAM_SUCCESS) {
 525                         free(ncpname);
 526                         break;
 527                 }
 528                 ret = cb(ncph, data);
 529                 free(ncph);
 530                 free(ncpname);
 531                 if (ret != 0) {
 532                         err = NWAM_WALK_HALTED;
 533                         break;
 534                 }
 535         }
 536         nwam_value_free(value);
 537         nwam_free_object_list(objlist);
 538 
 539         if (retp != NULL)
 540                 *retp = ret;
 541         return (err);
 542 }
 543 
 544 /*
 545  * Checks if NCP is read-only.  Only NWAM_NCP_NAME_AUTOMATIC is read-only
 546  * for all but the netadm user (which nwamd runs as).
 547  */
 548 nwam_error_t
 549 nwam_ncp_get_read_only(nwam_ncp_handle_t ncph, boolean_t *readp)
 550 {
 551         nwam_error_t err;
 552         char *name;
 553 
 554         assert(ncph != NULL && readp != NULL);
 555 
 556         if ((err = nwam_ncp_get_name(ncph, &name)) != NWAM_SUCCESS)
 557                 return (err);
 558 
 559         if (NWAM_NCP_AUTOMATIC(name))
 560                 *readp = !nwam_uid_is_special();
 561         else
 562                 *readp = B_FALSE;
 563 
 564         free(name);
 565         return (NWAM_SUCCESS);
 566 }
 567 
 568 /* Checks if NCU is writable depending on its parent */
 569 nwam_error_t
 570 nwam_ncu_get_read_only(nwam_ncu_handle_t ncuh, boolean_t *readp)
 571 {
 572         nwam_error_t err;
 573         nwam_ncp_handle_t ncph;
 574 
 575         assert(ncuh != NULL && readp != NULL);
 576 
 577         if ((err = nwam_ncu_get_ncp(ncuh, &ncph)) != NWAM_SUCCESS)
 578                 return (err);
 579 
 580         err = nwam_ncp_get_read_only(ncph, readp);
 581         nwam_ncp_free(ncph);
 582         return (err);
 583 }
 584 
 585 /* Returns true if the NCP is active */
 586 static boolean_t
 587 nwam_ncp_is_active(nwam_ncp_handle_t ncph)
 588 {
 589         char *active_ncp, *name;
 590         boolean_t ret;
 591 
 592         assert(ncph != NULL);
 593 
 594         /*
 595          * Determine which NCP is active via the nwamd/active_ncp property
 596          * value.  This allows us to determine which NCP is active even
 597          * if nwamd is not running.
 598          */
 599         if (nwam_ncp_get_name(ncph, &name) != NWAM_SUCCESS ||
 600             nwam_get_smf_string_property(NWAM_FMRI, NWAM_PG,
 601             NWAM_PROP_ACTIVE_NCP, &active_ncp) != NWAM_SUCCESS)
 602                 return (B_FALSE);
 603 
 604         ret = (strcmp(name, active_ncp) == 0);
 605 
 606         free(active_ncp);
 607         free(name);
 608 
 609         return (ret);
 610 }
 611 
 612 nwam_error_t
 613 nwam_ncp_destroy(nwam_ncp_handle_t ncph, uint64_t flags)
 614 {
 615         char *filename;
 616         nwam_error_t err;
 617         boolean_t read_only;
 618 
 619         assert(ncph != NULL);
 620 
 621         if ((err = nwam_ncp_get_read_only(ncph, &read_only)) != NWAM_SUCCESS)
 622                 return (err);
 623         if (read_only)
 624                 return (NWAM_ENTITY_NOT_DESTROYABLE);
 625 
 626         if (nwam_ncp_is_active(ncph))
 627                 return (NWAM_ENTITY_IN_USE);
 628 
 629         if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &filename))
 630             != NWAM_SUCCESS)
 631                 return (err);
 632 
 633         err = nwam_destroy(filename, ncph, flags);
 634         free(filename);
 635 
 636         return (NWAM_SUCCESS);
 637 }
 638 
 639 static nwam_error_t
 640 nwam_ncu_internal_name_to_name(const char *internalname,
 641     nwam_ncu_type_t *typep, char **namep)
 642 {
 643         char *prefixstr;
 644 
 645         assert(internalname != NULL && namep != NULL);
 646 
 647         if (strncasecmp(internalname, NWAM_NCU_LINK_NAME_PRE,
 648             strlen(NWAM_NCU_LINK_NAME_PRE)) == 0) {
 649                 prefixstr = NWAM_NCU_LINK_NAME_PRE;
 650                 *typep = NWAM_NCU_TYPE_LINK;
 651         } else if (strncasecmp(internalname, NWAM_NCU_INTERFACE_NAME_PRE,
 652             strlen(NWAM_NCU_INTERFACE_NAME_PRE)) == 0) {
 653                 prefixstr = NWAM_NCU_INTERFACE_NAME_PRE;
 654                 *typep = NWAM_NCU_TYPE_INTERFACE;
 655         } else {
 656                 return (NWAM_INVALID_ARG);
 657         }
 658 
 659         *namep = strdup(internalname + strlen(prefixstr));
 660         if (*namep == NULL)
 661                 return (NWAM_NO_MEMORY);
 662         return (NWAM_SUCCESS);
 663 }
 664 
 665 /* ARGSUSED2 */
 666 static int
 667 ncu_selectcb(struct nwam_handle *hp, uint64_t flags, void *data)
 668 {
 669         nwam_ncu_handle_t ncuh = hp;
 670         nwam_value_t typeval = NULL, classval = NULL;
 671         uint64_t type, class, matchflags, walkfilter;
 672 
 673         if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval)
 674             != NWAM_SUCCESS ||
 675             nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS, &classval)
 676             != NWAM_SUCCESS) {
 677                 if (typeval != NULL)
 678                         nwam_value_free(typeval);
 679                 return (NWAM_INVALID_ARG);
 680         }
 681         if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS ||
 682             nwam_value_get_uint64(classval, &class) != NWAM_SUCCESS) {
 683                 nwam_value_free(typeval);
 684                 nwam_value_free(classval);
 685                 return (NWAM_INVALID_ARG);
 686         }
 687 
 688         matchflags = nwam_ncu_type_to_flag(type) |
 689             nwam_ncu_class_to_flag(class);
 690         nwam_value_free(typeval);
 691         nwam_value_free(classval);
 692 
 693         if ((walkfilter = (flags & NWAM_WALK_FILTER_MASK)) == 0)
 694                 walkfilter = NWAM_FLAG_NCU_TYPE_CLASS_ALL;
 695 
 696         if (matchflags & walkfilter)
 697                 return (NWAM_SUCCESS);
 698         return (NWAM_INVALID_ARG);
 699 }
 700 
 701 nwam_error_t
 702 nwam_ncp_walk_ncus(nwam_ncp_handle_t ncph,
 703     int(*cb)(nwam_ncu_handle_t, void *), void *data, uint64_t flags, int *retp)
 704 {
 705         char *ncpfile;
 706         nwam_error_t err;
 707 
 708         assert(ncph != NULL && cb != NULL);
 709 
 710         if ((err = nwam_valid_flags(flags,
 711             NWAM_FLAG_NCU_TYPE_CLASS_ALL | NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS)
 712                 return (err);
 713 
 714         if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &ncpfile))
 715             != NWAM_SUCCESS)
 716                 return (err);
 717 
 718         err = nwam_walk(NWAM_OBJECT_TYPE_NCU, ncpfile, cb, data, flags,
 719             retp, ncu_selectcb);
 720         free(ncpfile);
 721 
 722         return (err);
 723 }
 724 
 725 void
 726 nwam_ncp_free(nwam_ncp_handle_t ncph)
 727 {
 728         nwam_free(ncph);
 729 }
 730 
 731 /*
 732  * Are ncu type and class compatible?
 733  */
 734 static boolean_t
 735 nwam_ncu_type_class_compatible(nwam_ncu_type_t type, nwam_ncu_class_t class)
 736 {
 737         switch (type) {
 738         case NWAM_NCU_TYPE_LINK:
 739                 return (class == NWAM_NCU_CLASS_PHYS);
 740         case NWAM_NCU_TYPE_INTERFACE:
 741                 return (class == NWAM_NCU_CLASS_IP);
 742         default:
 743                 return (B_FALSE);
 744         }
 745 }
 746 
 747 /* Name to validate may be internal name. If so, convert it before validating */
 748 static boolean_t
 749 valid_ncu_name(const char *name)
 750 {
 751         char *n;
 752         boolean_t ret;
 753         nwam_ncu_type_t type;
 754 
 755         if (nwam_ncu_internal_name_to_name(name, &type, &n) == NWAM_SUCCESS) {
 756 
 757                 ret = dladm_valid_linkname(n);
 758                 free(n);
 759         } else {
 760                 ret = dladm_valid_linkname(name);
 761         }
 762 
 763         return (ret);
 764 }
 765 
 766 nwam_error_t
 767 nwam_ncu_create(nwam_ncp_handle_t ncph, const char *name,
 768     nwam_ncu_type_t type, nwam_ncu_class_t class, nwam_ncu_handle_t *ncuhp)
 769 {
 770         nwam_ncu_handle_t ncuh;
 771         nwam_value_t typeval = NULL, classval = NULL, parentval = NULL;
 772         nwam_value_t enabledval = NULL;
 773         nwam_error_t err;
 774         boolean_t read_only;
 775         char *typedname;
 776 
 777         assert(ncph != NULL && name != NULL && ncuhp != NULL);
 778 
 779         if (!valid_ncu_name(name))
 780                 return (NWAM_INVALID_ARG);
 781 
 782         if ((err = nwam_ncp_get_read_only(ncph, &read_only)) != NWAM_SUCCESS)
 783                 return (err);
 784         if (read_only)
 785                 return (NWAM_ENTITY_READ_ONLY);
 786 
 787         if (nwam_ncu_read(ncph, name, type, 0, &ncuh) == NWAM_SUCCESS) {
 788                 nwam_ncu_free(ncuh);
 789                 return (NWAM_ENTITY_EXISTS);
 790         }
 791 
 792         if (!valid_ncu_name(name) ||
 793             !nwam_ncu_type_class_compatible(type, class))
 794                 return (NWAM_INVALID_ARG);
 795 
 796         if ((err = nwam_ncu_name_to_typed_name(name, type, &typedname))
 797             != NWAM_SUCCESS)
 798                 return (err);
 799 
 800         /* Create handle */
 801         if ((err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, typedname, ncuhp))
 802             != NWAM_SUCCESS)
 803                 return (err);
 804         free(typedname);
 805 
 806         /*
 807          * Create new object list for NCU.  The new NCU is initialized with
 808          * the appropriate type and class.
 809          */
 810         if ((err = nwam_alloc_object_list(&(*ncuhp)->nwh_data)) != NWAM_SUCCESS)
 811                 goto finish;
 812 
 813         if ((err = nwam_value_create_uint64(type, &typeval))
 814             != NWAM_SUCCESS ||
 815             (err = nwam_value_create_uint64(class, &classval))
 816             != NWAM_SUCCESS ||
 817             (err = nwam_value_create_string(ncph->nwh_name, &parentval))
 818             != NWAM_SUCCESS ||
 819             (err = nwam_value_create_boolean(B_TRUE, &enabledval))
 820             != NWAM_SUCCESS) {
 821                 goto finish;
 822         }
 823         if ((err = nwam_set_prop_value((*ncuhp)->nwh_data, NWAM_NCU_PROP_TYPE,
 824             typeval)) != NWAM_SUCCESS ||
 825             (err = nwam_set_prop_value((*ncuhp)->nwh_data, NWAM_NCU_PROP_CLASS,
 826             classval)) != NWAM_SUCCESS ||
 827             (err = nwam_set_prop_value((*ncuhp)->nwh_data,
 828             NWAM_NCU_PROP_PARENT_NCP, parentval)) != NWAM_SUCCESS ||
 829             (err = nwam_set_prop_value((*ncuhp)->nwh_data,
 830             NWAM_NCU_PROP_ENABLED, enabledval)) != NWAM_SUCCESS) {
 831                 goto finish;
 832         }
 833 
 834         /* Set default IP, datalink properties */
 835         if (type == NWAM_NCU_TYPE_INTERFACE && class == NWAM_NCU_CLASS_IP) {
 836 
 837                 uint64_t ver[] = { IPV4_VERSION, IPV6_VERSION };
 838                 uint64_t v6src[] = { NWAM_ADDRSRC_DHCP, NWAM_ADDRSRC_AUTOCONF };
 839                 uint_t vercnt = 2, v6srccnt = 2;
 840                 nwam_value_t ipver = NULL, v4addrsrc = NULL, v6addrsrc = NULL;
 841 
 842                 if ((err = nwam_value_create_uint64_array(ver, vercnt, &ipver))
 843                     != NWAM_SUCCESS ||
 844                     (err = nwam_value_create_uint64(NWAM_ADDRSRC_DHCP,
 845                     &v4addrsrc)) != NWAM_SUCCESS ||
 846                     (err = nwam_value_create_uint64_array(v6src, v6srccnt,
 847                     &v6addrsrc)) != NWAM_SUCCESS) {
 848                         nwam_value_free(ipver);
 849                         nwam_value_free(v4addrsrc);
 850                         goto finish;
 851                 }
 852                 if ((err = nwam_set_prop_value((*ncuhp)->nwh_data,
 853                     NWAM_NCU_PROP_IP_VERSION, ipver)) == NWAM_SUCCESS &&
 854                     (err = nwam_set_prop_value((*ncuhp)->nwh_data,
 855                     NWAM_NCU_PROP_IPV4_ADDRSRC, v4addrsrc)) == NWAM_SUCCESS) {
 856                         err = nwam_set_prop_value((*ncuhp)->nwh_data,
 857                             NWAM_NCU_PROP_IPV6_ADDRSRC, v6addrsrc);
 858                 }
 859                 nwam_value_free(ipver);
 860                 nwam_value_free(v4addrsrc);
 861                 nwam_value_free(v6addrsrc);
 862         } else {
 863                 nwam_value_t actval = NULL;
 864                 if ((err = nwam_value_create_uint64(NWAM_ACTIVATION_MODE_MANUAL,
 865                     &actval)) != NWAM_SUCCESS)
 866                         goto finish;
 867                 err = nwam_set_prop_value((*ncuhp)->nwh_data,
 868                     NWAM_NCU_PROP_ACTIVATION_MODE, actval);
 869                 nwam_value_free(actval);
 870         }
 871 
 872 finish:
 873         nwam_value_free(typeval);
 874         nwam_value_free(classval);
 875         nwam_value_free(parentval);
 876         nwam_value_free(enabledval);
 877         if (err != NWAM_SUCCESS) {
 878                 nwam_ncu_free(*ncuhp);
 879                 *ncuhp = NULL;
 880         }
 881         return (err);
 882 }
 883 
 884 nwam_error_t
 885 nwam_ncu_read(nwam_ncp_handle_t ncph, const char *name,
 886     nwam_ncu_type_t type, uint64_t flags, nwam_ncu_handle_t *ncuhp)
 887 {
 888         char *ncpfile, *typedname;
 889         nwam_error_t err, err_ip, err_link;
 890         nwam_ncu_handle_t ncuh_ip, ncuh_link;
 891 
 892         assert(ncph != NULL && name != NULL && ncuhp != NULL);
 893 
 894         if ((err = nwam_ncp_name_to_file(ncph->nwh_name, &ncpfile))
 895             != NWAM_SUCCESS)
 896                 return (err);
 897 
 898         if (type == NWAM_NCU_TYPE_ANY) {
 899 
 900                 free(ncpfile);
 901 
 902                 /*
 903                  * If we get to this point, we have discovered that no
 904                  * NCU type is discernable from name or type arguments.
 905                  * Either exactly one NCU called name must exist of either
 906                  * type, or the operation should fail.
 907                  */
 908                 err_ip = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_INTERFACE,
 909                     flags, &ncuh_ip);
 910                 err_link = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK,
 911                     flags, &ncuh_link);
 912 
 913                 *ncuhp = NULL;
 914 
 915                 if (err_ip == NWAM_SUCCESS && err_link == NWAM_SUCCESS) {
 916                         nwam_ncu_free(ncuh_ip);
 917                         nwam_ncu_free(ncuh_link);
 918                         err = NWAM_ENTITY_MULTIPLE_VALUES;
 919                 } else if (err_ip != NWAM_SUCCESS && err_link != NWAM_SUCCESS) {
 920                         err = NWAM_ENTITY_NOT_FOUND;
 921                 } else {
 922                         if (err_ip == NWAM_SUCCESS) {
 923                                 *ncuhp = ncuh_ip;
 924                         } else {
 925                                 *ncuhp = ncuh_link;
 926                         }
 927                         err = NWAM_SUCCESS;
 928                 }
 929 
 930                 return (err);
 931         }
 932         if ((err = nwam_ncu_name_to_typed_name(name, type, &typedname)) !=
 933             NWAM_SUCCESS) {
 934                 free(ncpfile);
 935                 return (err);
 936         }
 937         err = nwam_read(NWAM_OBJECT_TYPE_NCU, ncpfile, typedname, flags, ncuhp);
 938 
 939         free(typedname);
 940         free(ncpfile);
 941 
 942         return (err);
 943 }
 944 
 945 nwam_error_t
 946 nwam_ncu_get_name(nwam_ncu_handle_t ncuh, char **namep)
 947 {
 948         nwam_ncu_type_t type;
 949 
 950         assert(ncuh != NULL && namep != NULL);
 951 
 952         return (nwam_ncu_internal_name_to_name(ncuh->nwh_name, &type, namep));
 953 }
 954 
 955 nwam_error_t
 956 nwam_ncu_name_to_typed_name(const char *name, nwam_ncu_type_t type,
 957     char **typednamep)
 958 {
 959         char *prefixstr;
 960         size_t typednamesz;
 961 
 962         assert(name != NULL && typednamep != NULL);
 963 
 964         switch (type) {
 965         case NWAM_NCU_TYPE_INTERFACE:
 966                 prefixstr = NWAM_NCU_INTERFACE_NAME_PRE;
 967                 break;
 968         case NWAM_NCU_TYPE_LINK:
 969                 prefixstr = NWAM_NCU_LINK_NAME_PRE;
 970                 break;
 971         default:
 972                 return (NWAM_INVALID_ARG);
 973         }
 974         typednamesz = strlen(name) + strlen(prefixstr) + 1;
 975         if ((*typednamep = malloc(typednamesz)) == NULL)
 976                 return (NWAM_NO_MEMORY);
 977 
 978         /* Name may be already qualified by type */
 979         if (strncasecmp(prefixstr, name, strlen(prefixstr)) == 0) {
 980                 (void) snprintf(*typednamep, typednamesz, "%s", name);
 981         } else {
 982                 (void) snprintf(*typednamep, typednamesz, "%s%s",
 983                     prefixstr, name);
 984         }
 985 
 986         return (NWAM_SUCCESS);
 987 }
 988 
 989 nwam_error_t
 990 nwam_ncu_typed_name_to_name(const char *typed_name, nwam_ncu_type_t *typep,
 991     char **name)
 992 {
 993         return (nwam_ncu_internal_name_to_name(typed_name, typep, name));
 994 }
 995 
 996 void
 997 nwam_ncu_free(nwam_ncu_handle_t ncuh)
 998 {
 999         nwam_free(ncuh);
1000 }
1001 
1002 nwam_error_t
1003 nwam_ncu_copy(nwam_ncu_handle_t oldncuh, const char *newname,
1004     nwam_ncu_handle_t *newncuhp)
1005 {
1006         nwam_ncp_handle_t ncph;
1007         nwam_ncu_handle_t ncuh;
1008         nwam_error_t err;
1009         nwam_value_t typeval;
1010         uint64_t type;
1011         char *typednewname;
1012 
1013         assert(oldncuh != NULL && newname != NULL && newncuhp != NULL);
1014 
1015         if (nwam_ncu_get_prop_value(oldncuh, NWAM_NCU_PROP_TYPE,
1016             &typeval) != NWAM_SUCCESS) {
1017                 return (NWAM_INVALID_ARG);
1018         }
1019         if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS) {
1020                 nwam_value_free(typeval);
1021                 return (NWAM_INVALID_ARG);
1022         }
1023         nwam_value_free(typeval);
1024 
1025         /* check if newname NCU already exists */
1026         if ((err = nwam_ncu_get_ncp(oldncuh, &ncph)) != NWAM_SUCCESS)
1027                 return (err);
1028         if (nwam_ncu_read(ncph, newname, type, 0, &ncuh) == NWAM_SUCCESS) {
1029                 nwam_ncu_free(ncuh);
1030                 nwam_ncp_free(ncph);
1031                 return (NWAM_ENTITY_EXISTS);
1032         }
1033         nwam_ncp_free(ncph);
1034 
1035         if ((err = nwam_ncu_name_to_typed_name(newname, type, &typednewname))
1036             != NWAM_SUCCESS)
1037                 return (err);
1038 
1039         err = nwam_handle_create(NWAM_OBJECT_TYPE_NCU, typednewname, newncuhp);
1040         free(typednewname);
1041         if (err != NWAM_SUCCESS)
1042                 return (err);
1043         if ((err = nwam_dup_object_list(oldncuh->nwh_data,
1044             &((*newncuhp)->nwh_data))) != NWAM_SUCCESS) {
1045                 free(*newncuhp);
1046                 *newncuhp = NULL;
1047                 return (err);
1048         }
1049 
1050         return (NWAM_SUCCESS);
1051 }
1052 
1053 nwam_error_t
1054 nwam_ncu_delete_prop(nwam_ncu_handle_t ncuh, const char *propname)
1055 {
1056         boolean_t ro_ncu, ro_prop;
1057         nwam_error_t err;
1058         void *olddata;
1059 
1060         assert(ncuh != NULL && propname != NULL);
1061 
1062         if ((err = nwam_ncu_get_read_only(ncuh, &ro_ncu)) != NWAM_SUCCESS ||
1063             (err = nwam_ncu_prop_read_only(propname, &ro_prop)) != NWAM_SUCCESS)
1064                 return (err);
1065         if (ro_ncu || ro_prop)
1066                 return (NWAM_ENTITY_READ_ONLY);
1067 
1068         /*
1069          * Duplicate data, remove property and validate. If validation
1070          * fails, revert to data duplicated prior to remove.
1071          */
1072         if ((err = nwam_dup_object_list(ncuh->nwh_data, &olddata))
1073             != NWAM_SUCCESS)
1074                 return (err);
1075         if ((err = nwam_delete_prop(ncuh->nwh_data, propname))
1076             != NWAM_SUCCESS) {
1077                 nwam_free_object_list(ncuh->nwh_data);
1078                 ncuh->nwh_data = olddata;
1079                 return (err);
1080         }
1081         if ((err = nwam_ncu_validate(ncuh, NULL)) != NWAM_SUCCESS) {
1082                 nwam_free_object_list(ncuh->nwh_data);
1083                 ncuh->nwh_data = olddata;
1084                 return (err);
1085         }
1086         nwam_free_object_list(olddata);
1087 
1088         return (NWAM_SUCCESS);
1089 }
1090 
1091 nwam_error_t
1092 nwam_ncu_set_prop_value(nwam_ncu_handle_t ncuh, const char *propname,
1093     nwam_value_t value)
1094 {
1095         boolean_t ro_ncu, ro_prop;
1096         nwam_error_t err;
1097         nwam_ncp_handle_t ncph;
1098 
1099         assert(ncuh != NULL && propname != NULL && value != NULL);
1100 
1101         if ((err = nwam_ncu_get_read_only(ncuh, &ro_ncu)) != NWAM_SUCCESS ||
1102             (err = nwam_ncu_prop_read_only(propname, &ro_prop)) != NWAM_SUCCESS)
1103                 return (err);
1104         if (ro_ncu || ro_prop)
1105                 return (NWAM_ENTITY_READ_ONLY);
1106 
1107         err = nwam_ncu_get_ncp(ncuh, &ncph);
1108         if (err != NWAM_SUCCESS && err != NWAM_INVALID_ARG) {
1109                 /*
1110                  * If "parent" property doesn't exist, NWAM_INVALID_ARG
1111                  * is returned.  Allow the setting to continue.
1112                  */
1113                 return (err);
1114         }
1115         nwam_ncp_free(ncph);
1116 
1117         /* Need to ensure property, type and value are valid */
1118         if ((err = nwam_ncu_validate_prop(ncuh, propname, value))
1119             != NWAM_SUCCESS)
1120                 return (err);
1121 
1122         return (nwam_set_prop_value(ncuh->nwh_data, propname, value));
1123 }
1124 
1125 nwam_error_t
1126 nwam_ncu_get_prop_value(nwam_ncu_handle_t ncuh, const char *propname,
1127     nwam_value_t *valuep)
1128 {
1129         assert(ncuh != NULL && propname != NULL && valuep != NULL);
1130 
1131         return (nwam_get_prop_value(ncuh->nwh_data, propname, valuep));
1132 }
1133 
1134 nwam_error_t
1135 nwam_ncu_walk_props(nwam_ncu_handle_t ncuh,
1136     int (*cb)(const char *, nwam_value_t, void *),
1137     void *data, uint64_t flags, int *retp)
1138 {
1139         return (nwam_walk_props(ncuh, cb, data, flags, retp));
1140 }
1141 
1142 nwam_error_t
1143 nwam_ncu_get_ncp(nwam_ncu_handle_t ncuh, nwam_ncp_handle_t *ncphp)
1144 {
1145         nwam_error_t err;
1146         char *parentname = NULL;
1147 
1148         if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &parentname))
1149             != NWAM_SUCCESS ||
1150             (err = nwam_handle_create(NWAM_OBJECT_TYPE_NCP, parentname, ncphp))
1151             != NWAM_SUCCESS) {
1152                 if (parentname != NULL)
1153                         free(parentname);
1154                 return (err);
1155         }
1156         free(parentname);
1157 
1158         return (NWAM_SUCCESS);
1159 }
1160 
1161 nwam_error_t
1162 nwam_ncu_commit(nwam_ncu_handle_t ncuh, uint64_t flags)
1163 {
1164         nwam_error_t err;
1165         boolean_t read_only;
1166         char *ncpfile, *ncpname;
1167 
1168         assert(ncuh != NULL && ncuh->nwh_data != NULL);
1169 
1170         if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS)
1171                 return (err);
1172         if (read_only)
1173                 return (NWAM_ENTITY_READ_ONLY);
1174 
1175         if ((err = nwam_ncu_validate(ncuh, NULL)) != NWAM_SUCCESS ||
1176             (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname))
1177             != NWAM_SUCCESS)
1178                 return (err);
1179 
1180         if ((err = nwam_ncp_name_to_file(ncpname, &ncpfile)) != NWAM_SUCCESS) {
1181                 free(ncpname);
1182                 return (err);
1183         }
1184 
1185         err = nwam_commit(ncpfile, ncuh, flags);
1186 
1187         free(ncpname);
1188         free(ncpfile);
1189 
1190         return (err);
1191 }
1192 /* Get the NCU type */
1193 nwam_error_t
1194 nwam_ncu_get_ncu_type(nwam_ncu_handle_t ncuh, nwam_ncu_type_t *typep)
1195 {
1196         nwam_error_t err;
1197         nwam_value_t typeval;
1198         uint64_t type;
1199 
1200         if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval))
1201             != NWAM_SUCCESS)
1202                 return (err);
1203         err = nwam_value_get_uint64(typeval, &type);
1204         nwam_value_free(typeval);
1205         if (err != NWAM_SUCCESS)
1206                 return (err);
1207 
1208         *typep = type;
1209         return (NWAM_SUCCESS);
1210 }
1211 
1212 /* Get the NCU class */
1213 nwam_error_t
1214 nwam_ncu_get_ncu_class(nwam_ncu_handle_t ncuh, nwam_ncu_class_t *classp)
1215 {
1216         nwam_error_t err;
1217         nwam_value_t classval;
1218         uint64_t class;
1219 
1220         if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS,
1221             &classval)) != NWAM_SUCCESS)
1222                 return (err);
1223         err = nwam_value_get_uint64(classval, &class);
1224         nwam_value_free(classval);
1225         if (err != NWAM_SUCCESS)
1226                 return (err);
1227 
1228         *classp = class;
1229         return (NWAM_SUCCESS);
1230 }
1231 
1232 /*
1233  * Determine if the NCU has manual activation-mode or not.
1234  */
1235 nwam_error_t
1236 nwam_ncu_is_manual(nwam_ncu_handle_t ncuh, boolean_t *manualp)
1237 {
1238         nwam_error_t err;
1239         nwam_value_t actval;
1240         uint64_t activation;
1241 
1242         assert(ncuh != NULL);
1243 
1244         if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ACTIVATION_MODE,
1245             &actval)) != NWAM_SUCCESS)
1246                 return (err);
1247         err = nwam_value_get_uint64(actval, &activation);
1248         nwam_value_free(actval);
1249         if (err != NWAM_SUCCESS)
1250                 return (err);
1251 
1252         if (activation == NWAM_ACTIVATION_MODE_MANUAL)
1253                 *manualp = B_TRUE;
1254         else
1255                 *manualp = B_FALSE;
1256         return (NWAM_SUCCESS);
1257 }
1258 
1259 /* Determine if NCU is enabled or not */
1260 static nwam_error_t
1261 nwam_ncu_is_enabled(nwam_ncu_handle_t ncuh, boolean_t *enabledp)
1262 {
1263         nwam_error_t err;
1264         nwam_value_t enabledval;
1265 
1266         assert(ncuh != NULL);
1267 
1268         if ((err = nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_ENABLED,
1269             &enabledval)) != NWAM_SUCCESS)
1270                 return (err);
1271         err = nwam_value_get_boolean(enabledval, enabledp);
1272         nwam_value_free(enabledval);
1273         return (err);
1274 }
1275 
1276 /* Update the enabled property */
1277 static nwam_error_t
1278 nwam_ncu_update_enabled(nwam_ncu_handle_t ncuh, boolean_t enabled)
1279 {
1280         nwam_error_t err;
1281         nwam_value_t enabledval;
1282 
1283         if ((err = nwam_value_create_boolean(enabled, &enabledval))
1284             != NWAM_SUCCESS)
1285                 return (err);
1286         err = nwam_set_prop_value(ncuh->nwh_data, NWAM_NCU_PROP_ENABLED,
1287             enabledval);
1288         nwam_value_free(enabledval);
1289         if (err != NWAM_SUCCESS)
1290                 return (err);
1291         return (nwam_ncu_commit(ncuh, NWAM_FLAG_ENTITY_ENABLE));
1292 }
1293 
1294 /*
1295  * Make ncu active; fails if the NCU's parent NCP is not active.
1296  */
1297 nwam_error_t
1298 nwam_ncu_enable(nwam_ncu_handle_t ncuh)
1299 {
1300         char *ncpname = NULL;
1301         nwam_error_t err;
1302         nwam_ncu_type_t type;
1303         boolean_t read_only, enabled, manual;
1304 
1305         assert(ncuh != NULL);
1306 
1307         /* Don't allow NCUs of Automatic NCP to be enabled */
1308         if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS)
1309                 return (err);
1310         if (read_only)
1311                 return (NWAM_ENTITY_NOT_MANUAL);
1312 
1313         /* Link NCUs with manual activation-mode or IP NCUs can be enabled */
1314         if ((err = nwam_ncu_get_ncu_type(ncuh, &type)) != NWAM_SUCCESS)
1315                 return (err);
1316 
1317         if (type == NWAM_NCU_TYPE_LINK) {
1318                 if ((err = nwam_ncu_is_manual(ncuh, &manual)) != NWAM_SUCCESS)
1319                         return (err);
1320                 if (!manual)
1321                         return (NWAM_ENTITY_NOT_MANUAL);
1322         }
1323 
1324         /* Make sure NCU is not enabled */
1325         if ((err = nwam_ncu_is_enabled(ncuh, &enabled)) != NWAM_SUCCESS ||
1326             (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname))
1327             != NWAM_SUCCESS)
1328                 return (err);
1329 
1330         if (enabled) {
1331                 free(ncpname);
1332                 return (NWAM_SUCCESS);
1333         }
1334 
1335         if ((err = nwam_ncu_update_enabled(ncuh, B_TRUE)) != NWAM_SUCCESS) {
1336                 free(ncpname);
1337                 return (err);
1338         }
1339 
1340         err = nwam_enable(ncpname, ncuh);
1341         free(ncpname);
1342 
1343         /* nwamd may not be running, that's okay. */
1344         if (err == NWAM_ERROR_BIND)
1345                 return (NWAM_SUCCESS);
1346         else
1347                 return (err);
1348 }
1349 
1350 /*
1351  * Disable ncu; fails if the NCU's parent NCP is not active, or if the
1352  * NCU is not currently active.
1353  */
1354 nwam_error_t
1355 nwam_ncu_disable(nwam_ncu_handle_t ncuh)
1356 {
1357         char *ncpname = NULL;
1358         nwam_error_t err;
1359         nwam_ncu_type_t type;
1360         boolean_t read_only, enabled, manual;
1361 
1362         assert(ncuh != NULL);
1363 
1364         /* Don't allow NCUs of Automatic NCP to be disabled */
1365         if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS)
1366                 return (err);
1367         if (read_only)
1368                 return (NWAM_ENTITY_NOT_MANUAL);
1369 
1370         /* Link NCUs with manual activation-mode or IP NCUs can be disabled */
1371         if ((err = nwam_ncu_get_ncu_type(ncuh, &type)) != NWAM_SUCCESS)
1372                 return (err);
1373 
1374         if (type == NWAM_NCU_TYPE_LINK) {
1375                 if ((err = nwam_ncu_is_manual(ncuh, &manual)) != NWAM_SUCCESS)
1376                         return (err);
1377                 if (!manual)
1378                         return (NWAM_ENTITY_NOT_MANUAL);
1379         }
1380 
1381         /* Make sure NCU is enabled */
1382         if ((err = nwam_ncu_is_enabled(ncuh, &enabled)) != NWAM_SUCCESS ||
1383             (err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname))
1384             != NWAM_SUCCESS)
1385                 return (err);
1386 
1387         if (!enabled) {
1388                 free(ncpname);
1389                 return (NWAM_SUCCESS);
1390         }
1391 
1392         if ((err = nwam_ncu_update_enabled(ncuh, B_FALSE)) != NWAM_SUCCESS) {
1393                 free(ncpname);
1394                 return (err);
1395         }
1396 
1397         err = nwam_disable(ncpname, ncuh);
1398         free(ncpname);
1399 
1400         /* nwamd may not be running, that's okay. */
1401         if (err == NWAM_ERROR_BIND)
1402                 return (NWAM_SUCCESS);
1403         else
1404                 return (err);
1405 }
1406 
1407 nwam_error_t
1408 nwam_ncu_destroy(nwam_ncu_handle_t ncuh, uint64_t flags)
1409 {
1410         char *ncpname, *ncpfile;
1411         boolean_t read_only;
1412         nwam_error_t err;
1413 
1414         assert(ncuh != NULL);
1415 
1416         if ((err = nwam_ncu_get_read_only(ncuh, &read_only)) != NWAM_SUCCESS)
1417                 return (err);
1418         if (read_only)
1419                 return (NWAM_ENTITY_NOT_DESTROYABLE);
1420 
1421         if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname))
1422             != NWAM_SUCCESS)
1423                 return (err);
1424         if ((err = nwam_ncp_name_to_file(ncpname, &ncpfile))
1425             != NWAM_SUCCESS) {
1426                 free(ncpname);
1427                 return (err);
1428         }
1429 
1430         err = nwam_destroy(ncpfile, ncuh, flags);
1431 
1432         free(ncpname);
1433         free(ncpfile);
1434 
1435         return (err);
1436 }
1437 
1438 nwam_error_t
1439 nwam_ncu_get_prop_description(const char *propname, const char **descriptionp)
1440 {
1441         return (nwam_get_prop_description(ncu_prop_table, propname,
1442             descriptionp));
1443 }
1444 
1445 /* Get expected property data type */
1446 nwam_error_t
1447 nwam_ncu_get_prop_type(const char *propname, nwam_value_type_t *typep)
1448 {
1449         return (nwam_get_prop_type(ncu_prop_table, propname, typep));
1450 }
1451 
1452 nwam_error_t
1453 nwam_ncu_prop_read_only(const char *propname, boolean_t *readp)
1454 {
1455         if ((*readp = NWAM_NCU_PROP_SETONCE(propname)) == B_TRUE)
1456                 return (NWAM_SUCCESS);
1457 
1458         return (nwam_prop_read_only(ncu_prop_table, propname, readp));
1459 }
1460 
1461 nwam_error_t
1462 nwam_ncu_prop_multivalued(const char *propname, boolean_t *multip)
1463 {
1464         return (nwam_prop_multivalued(ncu_prop_table, propname, multip));
1465 }
1466 
1467 /*
1468  * Ensure that the properties in the ncu, determined by that ncu's
1469  * type and class, belong there.
1470  */
1471 static nwam_error_t
1472 nwam_ncu_validate_prop_membership(nwam_ncu_handle_t ncuh, const char *propname)
1473 {
1474         struct nwam_prop_table_entry *pte;
1475         nwam_value_t typeval, classval;
1476         uint64_t type, class;
1477         uint64_t typeflags = 0, classflags = 0;
1478 
1479         /* Get type/class from ncu */
1480         if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_TYPE, &typeval)
1481             != NWAM_SUCCESS)
1482                 return (NWAM_ENTITY_INVALID);
1483         if (nwam_value_get_uint64(typeval, &type) != NWAM_SUCCESS) {
1484                 nwam_value_free(typeval);
1485                 return (NWAM_ENTITY_INVALID);
1486         }
1487         typeflags = nwam_ncu_type_to_flag((nwam_ncu_type_t)type);
1488         nwam_value_free(typeval);
1489 
1490         if (nwam_ncu_get_prop_value(ncuh, NWAM_NCU_PROP_CLASS, &classval)
1491             != NWAM_SUCCESS)
1492                 return (NWAM_ENTITY_INVALID);
1493         if (nwam_value_get_uint64(classval, &class) != NWAM_SUCCESS) {
1494                 nwam_value_free(classval);
1495                 return (NWAM_ENTITY_INVALID);
1496         }
1497         classflags = nwam_ncu_class_to_flag((nwam_ncu_class_t)class);
1498         nwam_value_free(classval);
1499 
1500         if ((pte = nwam_get_prop_table_entry(ncu_prop_table, propname)) == NULL)
1501                 return (NWAM_INVALID_ARG);
1502 
1503         if (typeflags & pte->prop_type_membership &&
1504             classflags & pte->prop_class_membership) {
1505                 return (NWAM_SUCCESS);
1506         } else {
1507                 return (NWAM_ENTITY_INVALID_MEMBER);
1508         }
1509 }
1510 
1511 /* Validate property's ncu membership and type, number and range of values */
1512 nwam_error_t
1513 nwam_ncu_validate_prop(nwam_ncu_handle_t ncuh, const char *propname,
1514     nwam_value_t value)
1515 {
1516         nwam_error_t err;
1517 
1518         assert(ncuh != NULL && propname != NULL);
1519 
1520         /* First, determine if this property is valid for this ncu */
1521         if ((err = nwam_ncu_validate_prop_membership(ncuh, propname))
1522             != NWAM_SUCCESS)
1523                 return (err);
1524 
1525         return (nwam_validate_prop(ncu_prop_table, ncuh, propname, value));
1526 }
1527 
1528 /* Property-specific value validation functions follow */
1529 
1530 static nwam_error_t
1531 valid_type(nwam_value_t value)
1532 {
1533         uint64_t type;
1534 
1535         if (nwam_value_get_uint64(value, &type) != NWAM_SUCCESS ||
1536             type > NWAM_NCU_TYPE_INTERFACE)
1537                 return (NWAM_ENTITY_INVALID_VALUE);
1538         return (NWAM_SUCCESS);
1539 }
1540 
1541 static nwam_error_t
1542 valid_class(nwam_value_t value)
1543 {
1544         uint64_t class;
1545 
1546         if (nwam_value_get_uint64(value, &class) != NWAM_SUCCESS ||
1547             class > NWAM_NCU_CLASS_IP)
1548                 return (NWAM_ENTITY_INVALID_VALUE);
1549         return (NWAM_SUCCESS);
1550 }
1551 
1552 static nwam_error_t
1553 valid_ncp(nwam_value_t value)
1554 {
1555         char *ncp;
1556 
1557         if (nwam_value_get_string(value, &ncp) != NWAM_SUCCESS)
1558                 return (NWAM_ENTITY_INVALID_VALUE);
1559         return (NWAM_SUCCESS);
1560 }
1561 
1562 static nwam_error_t
1563 valid_priority_mode(nwam_value_t value)
1564 {
1565         uint64_t priority_mode;
1566 
1567         if (nwam_value_get_uint64(value, &priority_mode) != NWAM_SUCCESS ||
1568             priority_mode > NWAM_PRIORITY_MODE_ALL)
1569                 return (NWAM_ENTITY_INVALID_VALUE);
1570         return (NWAM_SUCCESS);
1571 }
1572 
1573 static nwam_error_t
1574 valid_ncu_activation_mode(nwam_value_t value)
1575 {
1576         uint64_t activation_mode;
1577 
1578         if (nwam_value_get_uint64(value, &activation_mode) != NWAM_SUCCESS)
1579                 return (NWAM_ENTITY_INVALID_VALUE);
1580 
1581         switch (activation_mode) {
1582         case NWAM_ACTIVATION_MODE_MANUAL:
1583         case NWAM_ACTIVATION_MODE_PRIORITIZED:
1584                 return (NWAM_SUCCESS);
1585         }
1586         return (NWAM_ENTITY_INVALID_VALUE);
1587 }
1588 
1589 /* ARGSUSED0 */
1590 static nwam_error_t
1591 valid_link_autopush(nwam_value_t value)
1592 {
1593         return (NWAM_SUCCESS);
1594 }
1595 
1596 static nwam_error_t
1597 valid_ip_version(nwam_value_t value)
1598 {
1599         uint64_t *versions;
1600         uint_t i, numvalues;
1601 
1602         if (nwam_value_get_uint64_array(value, &versions, &numvalues)
1603             != NWAM_SUCCESS)
1604                 return (NWAM_ENTITY_INVALID_VALUE);
1605 
1606         for (i = 0; i < numvalues; i++) {
1607                 if (versions[i] != IPV4_VERSION &&
1608                     versions[i] != IPV6_VERSION)
1609                 return (NWAM_ENTITY_INVALID_VALUE);
1610         }
1611         return (NWAM_SUCCESS);
1612 }
1613 
1614 static nwam_error_t
1615 valid_addrsrc_v4(nwam_value_t value)
1616 {
1617         uint64_t *addrsrc;
1618         uint_t i, numvalues;
1619 
1620         if (nwam_value_get_uint64_array(value, &addrsrc, &numvalues)
1621             != NWAM_SUCCESS)
1622                 return (NWAM_ENTITY_INVALID_VALUE);
1623 
1624         for (i = 0; i < numvalues; i++) {
1625                 if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
1626                     addrsrc[i] != NWAM_ADDRSRC_STATIC)
1627                         return (NWAM_ENTITY_INVALID_VALUE);
1628         }
1629         return (NWAM_SUCCESS);
1630 }
1631 
1632 static nwam_error_t
1633 valid_addrsrc_v6(nwam_value_t value)
1634 {
1635         uint64_t *addrsrc;
1636         uint_t i, numvalues;
1637         boolean_t dhcp_found = B_FALSE, autoconf_found = B_FALSE;
1638 
1639         if (nwam_value_get_uint64_array(value, &addrsrc, &numvalues)
1640             != NWAM_SUCCESS)
1641                 return (NWAM_ENTITY_INVALID_VALUE);
1642 
1643         for (i = 0; i < numvalues; i++) {
1644                 if (addrsrc[i] != NWAM_ADDRSRC_DHCP &&
1645                     addrsrc[i] != NWAM_ADDRSRC_STATIC &&
1646                     addrsrc[i] != NWAM_ADDRSRC_AUTOCONF)
1647                         return (NWAM_ENTITY_INVALID_VALUE);
1648                 if (addrsrc[i] == NWAM_ADDRSRC_DHCP)
1649                         dhcp_found = B_TRUE;
1650                 if (addrsrc[i] == NWAM_ADDRSRC_AUTOCONF)
1651                         autoconf_found = B_TRUE;
1652         }
1653         /*
1654          * DHCP and AUTOCONF need to be specified as v6 address sources
1655          * since there is no way to switch them off in NWAM at present.
1656          */
1657         if (dhcp_found && autoconf_found)
1658                 return (NWAM_SUCCESS);
1659         else
1660                 return (NWAM_ENTITY_INVALID_VALUE);
1661 }
1662 
1663 static nwam_error_t
1664 valid_reqhost(nwam_value_t value)
1665 {
1666         char *hostname;
1667 
1668         if (nwam_value_get_string(value, &hostname) != NWAM_SUCCESS)
1669                 return (NWAM_ENTITY_INVALID_VALUE);
1670         return (ipadm_is_valid_hostname(hostname) ? NWAM_SUCCESS
1671             : NWAM_ENTITY_INVALID_VALUE);
1672 }
1673 
1674 /* ARGSUSED0 */
1675 static nwam_error_t
1676 valid_link_mtu(nwam_value_t value)
1677 {
1678         return (NWAM_SUCCESS);
1679 }
1680 
1681 nwam_error_t
1682 nwam_ncu_validate(nwam_ncu_handle_t ncuh, const char **errpropp)
1683 {
1684         return (nwam_validate(ncu_prop_table, ncuh, errpropp));
1685 }
1686 
1687 /*
1688  * Given the ncu type and ncu class, return the list of properties that needs
1689  * to be set. Note this list is a complete property list that includes both
1690  * the required ones and the optional ones. Caller needs to free prop_list.
1691  */
1692 nwam_error_t
1693 nwam_ncu_get_default_proplist(nwam_ncu_type_t type, nwam_ncu_class_t class,
1694     const char ***prop_list, uint_t *numvalues)
1695 {
1696         uint64_t typeflags = nwam_ncu_type_to_flag(type);
1697         uint64_t classflags = nwam_ncu_class_to_flag(class);
1698 
1699         return (nwam_get_default_proplist(ncu_prop_table, typeflags,
1700             classflags, prop_list, numvalues));
1701 }
1702 
1703 nwam_error_t
1704 nwam_ncp_get_state(nwam_ncp_handle_t ncph, nwam_state_t *statep,
1705     nwam_aux_state_t *auxp)
1706 {
1707         return (nwam_get_state(ncph->nwh_name, ncph, statep, auxp));
1708 }
1709 
1710 nwam_error_t
1711 nwam_ncu_get_state(nwam_ncu_handle_t ncuh, nwam_state_t *statep,
1712     nwam_aux_state_t *auxp)
1713 {
1714         nwam_ncp_handle_t ncph;
1715         char *ncpname;
1716         nwam_error_t err;
1717 
1718         assert(ncuh != NULL);
1719 
1720         if ((err = nwam_ncu_get_ncp(ncuh, &ncph)) != NWAM_SUCCESS)
1721                 return (err);
1722         if (!nwam_ncp_is_active(ncph)) {
1723                 nwam_ncp_free(ncph);
1724                 return (NWAM_ENTITY_INVALID);
1725         }
1726         nwam_ncp_free(ncph);
1727 
1728         if ((err = nwam_ncu_get_parent_ncp_name(ncuh, &ncpname))
1729             != NWAM_SUCCESS)
1730                 return (err);
1731 
1732         err = nwam_request_state(NWAM_OBJECT_TYPE_NCU, ncuh->nwh_name, ncpname,
1733             statep, auxp);
1734         free(ncpname);
1735         return (err);
1736 }
1737 
1738 nwam_error_t
1739 nwam_ncp_get_active_priority_group(int64_t *priorityp)
1740 {
1741         return (nwam_request_active_priority_group(priorityp));
1742 }