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