xref: /illumos-gate/usr/src/lib/libnwam/common/libnwam_ncp.c (revision 30165b7f6753bc3d48c52319bed7ec7b3ea36b3c)
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 }
1743