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