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 <stdlib.h>
29 #include <strings.h>
30 #include <string.h>
31 
32 #include "libnwam_impl.h"
33 #include <libintl.h>
34 #include <libnwam.h>
35 
36 /*
37  * Generic object manipulation functions. Given an object handle and
38  * other parameters, create/destroy objects, walk them, walk their
39  * properties, modify/retrieve/delete properties, enable/disable them,
40  * etc. All object handles are "struct nwam_handle *" objects, sharing
41  * the same description based on the object type, name, original name
42  * (used in renaming) and associated data representing properties.
43  */
44 
45 nwam_error_t
46 nwam_handle_create(nwam_object_type_t type, const char *name,
47     struct nwam_handle **hpp)
48 {
49 
50 	assert(name != NULL && hpp != NULL);
51 
52 	if (strnlen(name, NWAM_MAX_NAME_LEN) > NWAM_MAX_NAME_LEN) {
53 		*hpp = NULL;
54 		return (NWAM_INVALID_ARG);
55 	}
56 
57 	if ((*hpp = calloc(1, sizeof (struct nwam_handle))) == NULL)
58 		return (NWAM_NO_MEMORY);
59 
60 	(*hpp)->nwh_object_type = type;
61 	(void) strlcpy((*hpp)->nwh_name, name, strlen(name) + 1);
62 	(*hpp)->nwh_committed = B_FALSE;
63 	(*hpp)->nwh_data = NULL;
64 
65 	return (NWAM_SUCCESS);
66 }
67 
68 /*
69  * Read object of specified type from dbname.
70  */
71 nwam_error_t
72 nwam_read(nwam_object_type_t type, const char *dbname, const char *name,
73     uint64_t flags, struct nwam_handle **hpp)
74 {
75 	nwam_error_t err;
76 	char dbname_copy[MAXPATHLEN];
77 
78 	assert(name != NULL && hpp != NULL);
79 
80 	if (dbname != NULL)
81 		(void) strlcpy(dbname_copy, dbname, sizeof (dbname_copy));
82 
83 	if ((err = nwam_valid_flags(flags, NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS)
84 		return (err);
85 	if ((err = nwam_handle_create(type, name, hpp)) != NWAM_SUCCESS)
86 		return (err);
87 
88 	if ((err = nwam_read_object_from_backend
89 	    (dbname != NULL ? dbname_copy : NULL,
90 	    type == NWAM_OBJECT_TYPE_NCP ? NULL : (*hpp)->nwh_name, flags,
91 	    &(*hpp)->nwh_data)) != NWAM_SUCCESS) {
92 		free(*hpp);
93 		*hpp = NULL;
94 		return (err);
95 	}
96 	if (type == NWAM_OBJECT_TYPE_NCP && dbname != NULL) {
97 		char *ncpname;
98 
99 		/*
100 		 * dbname_copy may have been changed due to case-insensitive
101 		 * match against the actual NCP configuration file.
102 		 */
103 		if (nwam_ncp_file_to_name(dbname_copy, &ncpname)
104 		    == NWAM_SUCCESS) {
105 			(void) strlcpy((*hpp)->nwh_name, ncpname,
106 			    sizeof ((*hpp)->nwh_name));
107 			free(ncpname);
108 		}
109 	}
110 
111 	(*hpp)->nwh_committed = B_TRUE;
112 
113 	return (NWAM_SUCCESS);
114 }
115 
116 /*
117  * Create simply creates the handle - the object-specific function must
118  * then fill in property values.
119  */
120 nwam_error_t
121 nwam_create(nwam_object_type_t type, const char *dbname, const char *name,
122     struct nwam_handle **hpp)
123 {
124 	struct nwam_handle *hp;
125 
126 	assert(hpp != NULL && name != NULL);
127 
128 	if (nwam_read(type, dbname, name, 0, &hp) == NWAM_SUCCESS) {
129 		nwam_free(hp);
130 		return (NWAM_ENTITY_EXISTS);
131 	}
132 	/* Create handle */
133 	return (nwam_handle_create(type, name, hpp));
134 }
135 
136 nwam_error_t
137 nwam_get_name(struct nwam_handle *hp, char **namep)
138 {
139 	assert(hp != NULL && namep != NULL);
140 
141 	if ((*namep = strdup(hp->nwh_name)) == NULL) {
142 		*namep = NULL;
143 		return (NWAM_NO_MEMORY);
144 	}
145 	return (NWAM_SUCCESS);
146 }
147 
148 nwam_error_t
149 nwam_set_name(struct nwam_handle *hp, const char *name)
150 {
151 	assert(hp != NULL && name != NULL);
152 
153 	if (hp->nwh_committed)
154 		return (NWAM_ENTITY_READ_ONLY);
155 
156 	if (strlen(name) >= sizeof (hp->nwh_name))
157 		return (NWAM_INVALID_ARG);
158 
159 	(void) strcpy(hp->nwh_name, name);
160 
161 	return (NWAM_SUCCESS);
162 }
163 
164 /* Compare object names c1 and c2 using strcasecmp() */
165 static int
166 name_cmp(const void *c1, const void *c2)
167 {
168 	nwam_ncu_type_t t1, t2;
169 	char		*n1, *n2;
170 
171 	/* If c1 and c2 are typed NCU names, compare names without the types */
172 	if (nwam_ncu_typed_name_to_name(*(const char **)c1, &t1, &n1)
173 	    == NWAM_SUCCESS &&
174 	    nwam_ncu_typed_name_to_name(*(const char **)c2, &t2, &n2)
175 	    == NWAM_SUCCESS) {
176 		int ret = strcasecmp(n1, n2);
177 		free(n1);
178 		free(n2);
179 
180 		/* For NCUs with the same name, compare their types */
181 		if (ret == 0) {
182 			if (t1 < t2)
183 				ret = -1;
184 			else if (t1 > t2)
185 				ret = 1;
186 		}
187 		return (ret);
188 	}
189 
190 	return (strcasecmp(*(const char **)c1, *(const char **)c2));
191 }
192 
193 /*
194  * Generic walk function takes the standard walk arguments, and in addition
195  * takes a selection callback that is object-specific. If this returns
196  * 0, the object is a valid selection for the walk and the callback is called.
197  * Otherwise, it is skipped.
198  */
199 nwam_error_t
200 nwam_walk(nwam_object_type_t type, const char *dbname,
201     int(*cb)(struct nwam_handle *, void *),
202     void *data, uint64_t flags, int *retp,
203     int(*selectcb)(struct nwam_handle *, uint64_t, void *))
204 {
205 	void *objlist;
206 	nwam_value_t value;
207 	char **object_names;
208 	uint_t i, num_objects = 0;
209 	struct nwam_handle *hp;
210 	nwam_error_t err;
211 	int ret = 0;
212 
213 	assert(cb != NULL);
214 
215 	/*
216 	 * To walk a set of objects, call nwam_read_object_from_backend()
217 	 * with a "dbname" argument set to the container db name and
218 	 * the object name set to NULL. This returns an nvlist with one
219 	 * member - the NWAM_OBJECT_NAMES_STRING - and the values it contains
220 	 * represent the names of the objects.  Read each in turn, calling
221 	 * the callback function.
222 	 */
223 	if ((err = nwam_read_object_from_backend((char *)dbname, NULL, flags,
224 	    &objlist)) != NWAM_SUCCESS) {
225 		if (err == NWAM_ENTITY_NOT_FOUND) {
226 			/*
227 			 * This indicates the dbname container is not present.
228 			 * Do not pass back an error in this case, since it is
229 			 * valid for a container not to exist.
230 			 */
231 			return (NWAM_SUCCESS);
232 		}
233 		return (err);
234 	}
235 
236 	if ((err = nwam_get_prop_value(objlist, NWAM_OBJECT_NAMES_STRING,
237 	    &value)) != NWAM_SUCCESS) {
238 		nwam_free_object_list(objlist);
239 		return (err);
240 	}
241 	err = nwam_value_get_string_array(value, &object_names, &num_objects);
242 	nwam_free_object_list(objlist);
243 	if (err != NWAM_SUCCESS) {
244 		nwam_value_free(value);
245 		return (err);
246 	}
247 
248 	/* sort the object names alphabetically */
249 	qsort(object_names, num_objects, sizeof (char *), name_cmp);
250 
251 	for (i = 0; i < num_objects; i++) {
252 		err = nwam_read(type, dbname, object_names[i],
253 		    flags & NWAM_FLAG_GLOBAL_MASK, &hp);
254 		/* An object may have disappeared.  If so, skip it. */
255 		if (err == NWAM_ENTITY_NOT_FOUND)
256 			continue;
257 		if (err != NWAM_SUCCESS) {
258 			nwam_value_free(value);
259 			return (err);
260 		}
261 		if ((selectcb == NULL) || (selectcb(hp, flags, data) == 0)) {
262 			ret = cb(hp, data);
263 			if (ret != 0) {
264 				nwam_free(hp);
265 				nwam_value_free(value);
266 				if (retp != NULL)
267 					*retp = ret;
268 				return (NWAM_WALK_HALTED);
269 			}
270 		}
271 		nwam_free(hp);
272 	}
273 	nwam_value_free(value);
274 
275 	if (retp != NULL)
276 		*retp = ret;
277 	return (err);
278 }
279 
280 void
281 nwam_free(struct nwam_handle *hp)
282 {
283 	if (hp != NULL) {
284 		if (hp->nwh_data != NULL)
285 			nwam_free_object_list(hp->nwh_data);
286 		free(hp);
287 	}
288 }
289 
290 /*
291  * Copy object represented by oldhp to an object newname, all in container
292  * dbname.
293  */
294 nwam_error_t
295 nwam_copy(const char *dbname, struct nwam_handle *oldhp, const char *newname,
296     struct nwam_handle **newhpp)
297 {
298 	nwam_error_t err;
299 	struct nwam_handle *hp;
300 
301 	assert(oldhp != NULL && newname != NULL && newhpp != NULL);
302 
303 	if (nwam_read(oldhp->nwh_object_type, dbname, newname, 0, &hp)
304 	    == NWAM_SUCCESS) {
305 		nwam_free(hp);
306 		return (NWAM_ENTITY_EXISTS);
307 	}
308 
309 	if ((err = nwam_handle_create(oldhp->nwh_object_type, newname, newhpp))
310 	    != NWAM_SUCCESS)
311 		return (err);
312 	if ((err = nwam_dup_object_list(oldhp->nwh_data,
313 	    &((*newhpp)->nwh_data))) != NWAM_SUCCESS) {
314 		nwam_free(*newhpp);
315 		*newhpp = NULL;
316 		return (err);
317 	}
318 
319 	return (NWAM_SUCCESS);
320 }
321 
322 /* ARGSUSED3 */
323 nwam_error_t
324 nwam_walk_props(struct nwam_handle *hp,
325     int (*cb)(const char *, nwam_value_t, void *),
326     void *data, uint64_t flags, int *retp)
327 {
328 	char *lastpropname = NULL, *propname;
329 	nwam_value_t value;
330 	nwam_error_t err;
331 	int ret = 0;
332 
333 	assert(hp != NULL && hp->nwh_data != NULL && cb != NULL);
334 
335 	if ((err = nwam_valid_flags(flags, 0)) != NWAM_SUCCESS)
336 		return (err);
337 	while ((err = nwam_next_object_prop(hp->nwh_data, lastpropname,
338 	    &propname, &value)) == NWAM_SUCCESS) {
339 
340 		ret = cb(propname, value, data);
341 		if (ret != 0)
342 			err = NWAM_WALK_HALTED;
343 
344 		/* Free value */
345 		nwam_value_free(value);
346 
347 		if (err != NWAM_SUCCESS)
348 			break;
349 
350 		lastpropname = propname;
351 	}
352 
353 	if (retp != NULL)
354 		*retp = ret;
355 	if (err == NWAM_SUCCESS || err == NWAM_LIST_END)
356 		return (NWAM_SUCCESS);
357 	return (err);
358 }
359 
360 /*
361  * Note that prior to calling the generic commit function, object-specific
362  * validation should be carried out.
363  */
364 nwam_error_t
365 nwam_commit(const char *dbname, struct nwam_handle *hp, uint64_t flags)
366 {
367 	nwam_error_t err;
368 	uint64_t iflags = flags;
369 	boolean_t is_ncu;
370 	struct nwam_handle *testhp;
371 	nwam_action_t action;
372 
373 	assert(hp != NULL);
374 
375 	/*
376 	 * NWAM_FLAG_ENTITY_KNOWN_WLAN is only used for Known WLANs and
377 	 * NWAM_FLAG_ENTITY_ENABLE is used for other objects (during enable
378 	 * and disable).
379 	 */
380 	if ((err = nwam_valid_flags(flags,
381 	    NWAM_FLAG_BLOCKING | NWAM_FLAG_CREATE |
382 	    (hp->nwh_object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN ?
383 	    NWAM_FLAG_ENTITY_KNOWN_WLAN : NWAM_FLAG_ENTITY_ENABLE)))
384 	    != NWAM_SUCCESS)
385 		return (err);
386 
387 	is_ncu = (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU);
388 
389 	/*
390 	 * Does object already exist? If not, action is ADD, otherwise REFRESH.
391 	 */
392 	switch (nwam_read(hp->nwh_object_type, (char *)dbname, hp->nwh_name, 0,
393 	    &testhp)) {
394 	case NWAM_ENTITY_NOT_FOUND:
395 		action = NWAM_ACTION_ADD;
396 		break;
397 	case NWAM_SUCCESS:
398 		nwam_free(testhp);
399 		if (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP)
400 			return (NWAM_ENTITY_EXISTS);
401 		/* FALLTHRU */
402 	default:
403 		action = NWAM_ACTION_REFRESH;
404 		break;
405 	}
406 
407 	err = nwam_update_object_in_backend((char *)dbname,
408 	    hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP ? NULL : hp->nwh_name,
409 	    iflags, hp->nwh_data);
410 	if (err != NWAM_SUCCESS)
411 		return (err);
412 
413 	hp->nwh_committed = B_TRUE;
414 
415 	/*
416 	 * Tell nwamd to reread this object.  For NCUs, we need to convert
417 	 * the dbname to the NCP name in order to pass it to nwamd.
418 	 */
419 	if (is_ncu) {
420 		char *ncpname;
421 
422 		if (nwam_ncp_file_to_name(dbname, &ncpname) == NWAM_SUCCESS) {
423 			(void) nwam_request_action(hp->nwh_object_type,
424 			    hp->nwh_name, ncpname, action);
425 			free(ncpname);
426 		}
427 	} else {
428 		(void) nwam_request_action(hp->nwh_object_type, hp->nwh_name,
429 		    NULL, action);
430 	}
431 	return (NWAM_SUCCESS);
432 }
433 
434 static boolean_t
435 nwam_is_active(struct nwam_handle *hp)
436 {
437 	nwam_state_t state;
438 	nwam_aux_state_t aux;
439 
440 	return ((nwam_get_state(NULL, hp, &state, &aux) == NWAM_SUCCESS &&
441 	    state == NWAM_STATE_ONLINE));
442 }
443 
444 nwam_error_t
445 nwam_destroy(const char *dbname, struct nwam_handle *hp, uint64_t flags)
446 {
447 	nwam_error_t err;
448 	char *name;
449 	boolean_t is_ncp, is_ncu;
450 
451 	assert(hp != NULL);
452 
453 	/* NWAM_FLAG_ENTITY_KNOWN_WLAN is only used for Known WLANs */
454 	if ((err = nwam_valid_flags(flags,
455 	    NWAM_FLAG_BLOCKING | NWAM_FLAG_DO_NOT_FREE |
456 	    (hp->nwh_object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN ?
457 	    NWAM_FLAG_ENTITY_KNOWN_WLAN : 0))) != NWAM_SUCCESS)
458 		return (err);
459 
460 	is_ncp = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP;
461 	is_ncu = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU;
462 	name = hp->nwh_name;
463 
464 	/* Check if object is active */
465 	if (!is_ncp && !is_ncu && nwam_is_active(hp))
466 		return (NWAM_ENTITY_IN_USE);
467 
468 	/* For NCPs, just remove the dbname file, otherwise remove the object */
469 	err = nwam_remove_object_from_backend((char *)dbname,
470 	    is_ncp ? NULL : name, flags);
471 
472 	/*
473 	 * Tell nwamd to remove this object.  For NCUs, we need to convert the
474 	 * dbname filename to the NCP name to pass it to nwamd.
475 	 */
476 	if (is_ncu) {
477 		char *ncpname;
478 
479 		if (nwam_ncp_file_to_name(dbname, &ncpname) == NWAM_SUCCESS) {
480 			(void) nwam_request_action(hp->nwh_object_type, name,
481 			    ncpname, NWAM_ACTION_DESTROY);
482 			free(ncpname);
483 		}
484 	} else {
485 		(void) nwam_request_action(hp->nwh_object_type, name, NULL,
486 		    NWAM_ACTION_DESTROY);
487 	}
488 
489 	if ((err == NWAM_SUCCESS) && !(flags & NWAM_FLAG_DO_NOT_FREE))
490 		nwam_free(hp);
491 
492 	return (err);
493 }
494 
495 /*
496  * Enable/disable functions assume prior checking of activation mode
497  * to ensure an enable/disable action is valid for the object. "parent" in these
498  * functions specifies the NCP for NCUs.
499  */
500 nwam_error_t
501 nwam_enable(const char *parent, struct nwam_handle *hp)
502 {
503 	return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
504 	    parent, NWAM_ACTION_ENABLE));
505 }
506 
507 nwam_error_t
508 nwam_disable(const char *parent, struct nwam_handle *hp)
509 {
510 	return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
511 	    parent, NWAM_ACTION_DISABLE));
512 }
513 
514 nwam_error_t
515 nwam_get_state(const char *parent, struct nwam_handle *hp, nwam_state_t *statep,
516     nwam_aux_state_t *auxp)
517 {
518 	return (nwam_request_state(hp->nwh_object_type, hp->nwh_name, parent,
519 	    statep, auxp));
520 }
521 
522 struct nwam_prop_table_entry *
523 nwam_get_prop_table_entry(struct nwam_prop_table table, const char *propname)
524 {
525 	struct nwam_prop_table_entry *cur = table.entries;
526 	struct nwam_prop_table_entry *end = cur + table.num_entries;
527 
528 	assert(propname != NULL);
529 
530 	for (; cur < end; cur++) {
531 		if (strcmp(propname, cur->prop_name) == 0)
532 			return (cur);
533 	}
534 	return (NULL);
535 }
536 
537 nwam_error_t
538 nwam_get_prop_description(struct nwam_prop_table table, const char *propname,
539     const char **descriptionp)
540 {
541 	struct nwam_prop_table_entry *pte;
542 
543 	assert(propname != NULL && descriptionp != NULL);
544 
545 	if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL) {
546 		*descriptionp = NULL;
547 		return (NWAM_INVALID_ARG);
548 	}
549 
550 	*descriptionp = dgettext(TEXT_DOMAIN, pte->prop_description);
551 	return (NWAM_SUCCESS);
552 }
553 
554 nwam_error_t
555 nwam_get_prop_type(struct nwam_prop_table table, const char *propname,
556     nwam_value_type_t *typep)
557 {
558 	struct nwam_prop_table_entry *pte;
559 
560 	assert(propname != NULL && typep != NULL);
561 
562 	if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
563 		return (NWAM_INVALID_ARG);
564 
565 	*typep = pte->prop_type;
566 
567 	return (NWAM_SUCCESS);
568 }
569 
570 nwam_error_t
571 nwam_prop_multivalued(struct nwam_prop_table table, const char *propname,
572     boolean_t *multip)
573 {
574 	struct nwam_prop_table_entry *pte;
575 
576 	assert(propname != NULL && multip != NULL);
577 
578 	if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
579 		return (NWAM_INVALID_ARG);
580 
581 	if (pte->prop_max_numvalues > 1)
582 		*multip = B_TRUE;
583 	else
584 		*multip = B_FALSE;
585 
586 	return (NWAM_SUCCESS);
587 }
588 
589 nwam_error_t
590 nwam_prop_read_only(struct nwam_prop_table table, const char *propname,
591     boolean_t *readp)
592 {
593 	struct nwam_prop_table_entry *pte;
594 
595 	assert(propname != NULL && readp != NULL);
596 
597 	if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
598 		return (NWAM_INVALID_ARG);
599 
600 	*readp = (pte->prop_is_readonly && !nwam_uid_is_netadm());
601 
602 	return (NWAM_SUCCESS);
603 }
604 
605 /*
606  * Structure used to pass in prop table and errprop string pointer to internal
607  * validate function.
608  */
609 struct validate_internal_arg {
610 	struct nwam_prop_table table;
611 	const char **errpropp;
612 };
613 
614 /*
615  * Callback used by nwam_walk_props() in nwam_validate(), and
616  * by nwam_validate_prop() to determine that the number, type and
617  * range of values are correct, and that validation function (if present)
618  * succeeds.
619  */
620 static int
621 nwam_validate_prop_internal(const char *propname, nwam_value_t value,
622     void *arg)
623 {
624 	struct validate_internal_arg *via = arg;
625 	struct nwam_prop_table table = via->table;
626 	const char **errpropp = via->errpropp;
627 	struct nwam_prop_table_entry *pte;
628 	nwam_error_t err;
629 	nwam_value_type_t type;
630 	uint_t numvalues;
631 	int i;
632 
633 	if ((err = nwam_value_get_numvalues(value, &numvalues))
634 	    != NWAM_SUCCESS ||
635 	    (err = nwam_value_get_type(value, &type)) != NWAM_SUCCESS) {
636 		if (errpropp != NULL)
637 			*errpropp = propname;
638 		return (err);
639 	}
640 	if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
641 		return (NWAM_INVALID_ARG);
642 
643 	/* have we get expected number of values? */
644 	if (numvalues < pte->prop_min_numvalues ||
645 	    numvalues > pte->prop_max_numvalues) {
646 		if (errpropp != NULL)
647 			*errpropp = propname;
648 		if (numvalues < 1)
649 			return (NWAM_ENTITY_NO_VALUE);
650 		else
651 			return (NWAM_ENTITY_INVALID_VALUE);
652 	}
653 	/* Ensure type matches */
654 	if (numvalues > 0) {
655 		for (i = 0; i < numvalues; i++) {
656 			if (pte->prop_type != type) {
657 				if (errpropp != NULL)
658 					*errpropp = propname;
659 				return (NWAM_ENTITY_TYPE_MISMATCH);
660 
661 			}
662 		}
663 	}
664 	/* Call property-specific validation function */
665 	if (pte->prop_validate != NULL) {
666 		err = pte->prop_validate(value);
667 		if (err != NWAM_SUCCESS && errpropp != NULL)
668 			*errpropp = propname;
669 		return (err);
670 	}
671 
672 	return (NWAM_SUCCESS);
673 }
674 
675 nwam_error_t
676 nwam_validate_prop(struct nwam_prop_table table, struct nwam_handle *hp,
677     const char *propname, nwam_value_t value)
678 {
679 	struct validate_internal_arg via;
680 
681 	assert(hp != NULL && propname != NULL);
682 
683 	via.table = table;
684 	via.errpropp = NULL;
685 
686 	return ((nwam_error_t)nwam_validate_prop_internal(propname,
687 	    value, &via));
688 }
689 
690 nwam_error_t
691 nwam_validate(struct nwam_prop_table table, struct nwam_handle *hp,
692     const char **errpropp)
693 {
694 	struct validate_internal_arg via;
695 	nwam_error_t err1, err2;
696 
697 	assert(hp != NULL);
698 
699 	via.table = table;
700 	via.errpropp = errpropp;
701 
702 	err1 = nwam_walk_props(hp, nwam_validate_prop_internal, &via,
703 	    0, (int *)&err2);
704 	if (err1 != NWAM_SUCCESS)
705 		return (err2);
706 	return (NWAM_SUCCESS);
707 }
708 
709 /*
710  * Given the type and class flag representations, return the list of properties
711  * that can be set for that type/class combination. Note this list is a complete
712  * property list that includes both the required and the optional properties.
713  * The type and class flags are only used for NCU objects at present.
714  *
715  * Caller needs to free prop_list.
716  */
717 nwam_error_t
718 nwam_get_default_proplist(struct nwam_prop_table table,
719     uint64_t type, uint64_t class, const char ***prop_list, uint_t *numvalues)
720 {
721 	struct nwam_prop_table_entry *cur = table.entries;
722 	struct nwam_prop_table_entry *end = cur + table.num_entries;
723 	int i = 0;
724 	const char **list = NULL;
725 
726 	assert(prop_list != NULL && numvalues != NULL);
727 
728 	/* Construct a list of all properties for required type/class */
729 	list = calloc(table.num_entries, sizeof (char *));
730 	if (list == NULL) {
731 		*prop_list = NULL;
732 		*numvalues = 0;
733 		return (NWAM_NO_MEMORY);
734 	}
735 	for (; cur < end; cur++) {
736 		if (((type & cur->prop_type_membership) == 0) ||
737 		    ((class & cur->prop_class_membership) == 0))
738 			continue;
739 		list[i++] = cur->prop_name;
740 	}
741 	*numvalues = i;
742 	*prop_list = list;
743 	return (NWAM_SUCCESS);
744 }
745