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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <libdlwlan.h>
32 #include <libnvpair.h>
33 
34 #include "libnwam_impl.h"
35 #include <libnwam_priv.h>
36 #include <libnwam.h>
37 
38 /*
39  * Internal implementation of libnwam in-memory objects and values.  Objects
40  * are nvlists.
41  */
42 
43 void
44 nwam_value_free(nwam_value_t value)
45 {
46 	uint_t i;
47 
48 	if (value == NULL)
49 		return;
50 
51 	switch (value->nwv_value_type) {
52 	case NWAM_VALUE_TYPE_BOOLEAN:
53 		free(value->nwv_values.nwv_boolean);
54 		break;
55 	case NWAM_VALUE_TYPE_INT64:
56 		free(value->nwv_values.nwv_int64);
57 		break;
58 	case NWAM_VALUE_TYPE_UINT64:
59 		free(value->nwv_values.nwv_uint64);
60 		break;
61 	case NWAM_VALUE_TYPE_STRING:
62 		for (i = 0; i < value->nwv_value_numvalues; i++)
63 			free(value->nwv_values.nwv_string[i]);
64 		free(value->nwv_values.nwv_string);
65 		break;
66 	}
67 	free(value);
68 }
69 
70 nwam_error_t
71 nwam_value_create(nwam_value_type_t value_type, void *values, uint_t numvalues,
72     nwam_value_t *valuep)
73 {
74 	nwam_value_t newvalue;
75 	boolean_t *values_boolean;
76 	int64_t *values_int64;
77 	uint64_t *values_uint64;
78 	char **values_string;
79 	int i, j;
80 	nwam_error_t err = NWAM_SUCCESS;
81 
82 	*valuep = NULL;
83 
84 	if ((newvalue = calloc(1, sizeof (struct nwam_value))) == NULL)
85 		return (NWAM_NO_MEMORY);
86 
87 	newvalue->nwv_value_type = value_type;
88 	newvalue->nwv_value_numvalues = numvalues;
89 
90 	switch (value_type) {
91 	case NWAM_VALUE_TYPE_BOOLEAN:
92 		values_boolean = values;
93 		if ((newvalue->nwv_values.nwv_boolean =
94 		    calloc(numvalues, sizeof (boolean_t))) == NULL) {
95 			free(newvalue);
96 			return (NWAM_NO_MEMORY);
97 		}
98 		for (i = 0; i < numvalues; i++)
99 			newvalue->nwv_values.nwv_boolean[i] = values_boolean[i];
100 		break;
101 	case NWAM_VALUE_TYPE_INT64:
102 		values_int64 = values;
103 		if ((newvalue->nwv_values.nwv_int64 =
104 		    calloc(numvalues, sizeof (int64_t))) == NULL) {
105 			free(newvalue);
106 			return (NWAM_NO_MEMORY);
107 		}
108 		for (i = 0; i < numvalues; i++)
109 			newvalue->nwv_values.nwv_int64[i] = values_int64[i];
110 		break;
111 	case NWAM_VALUE_TYPE_UINT64:
112 		values_uint64 = values;
113 		if ((newvalue->nwv_values.nwv_uint64 =
114 		    calloc(numvalues, sizeof (uint64_t))) == NULL) {
115 			free(newvalue);
116 			return (NWAM_NO_MEMORY);
117 		}
118 		for (i = 0; i < numvalues; i++)
119 			newvalue->nwv_values.nwv_uint64[i] = values_uint64[i];
120 		break;
121 	case NWAM_VALUE_TYPE_STRING:
122 		values_string = values;
123 		if ((newvalue->nwv_values.nwv_string =
124 		    calloc(numvalues, sizeof (char *))) == NULL) {
125 			free(newvalue);
126 			return (NWAM_NO_MEMORY);
127 		}
128 		for (i = 0; i < numvalues; i++) {
129 			if (strnlen(values_string[i], NWAM_MAX_VALUE_LEN) ==
130 			    NWAM_MAX_VALUE_LEN) {
131 				err = NWAM_ENTITY_INVALID_VALUE;
132 			} else if ((newvalue->nwv_values.nwv_string[i] =
133 			    strdup(values_string[i])) == NULL) {
134 				err = NWAM_NO_MEMORY;
135 			}
136 			if (err != NWAM_SUCCESS) {
137 				for (j = 0; j < i; j++)
138 					free(
139 					    newvalue->nwv_values.nwv_string[i]);
140 				free(newvalue->nwv_values.nwv_string);
141 				free(newvalue);
142 				return (err);
143 			}
144 		}
145 		break;
146 	default:
147 		break;
148 	}
149 
150 	*valuep = newvalue;
151 	return (NWAM_SUCCESS);
152 }
153 
154 nwam_error_t
155 nwam_value_copy(nwam_value_t old, nwam_value_t *newp)
156 {
157 	void *values;
158 
159 	assert(old != NULL && newp != NULL);
160 
161 	switch (old->nwv_value_type) {
162 	case NWAM_VALUE_TYPE_BOOLEAN:
163 		values = old->nwv_values.nwv_boolean;
164 		break;
165 	case NWAM_VALUE_TYPE_INT64:
166 		values = old->nwv_values.nwv_int64;
167 		break;
168 	case NWAM_VALUE_TYPE_UINT64:
169 		values = old->nwv_values.nwv_uint64;
170 		break;
171 	case NWAM_VALUE_TYPE_STRING:
172 		values = old->nwv_values.nwv_string;
173 		break;
174 	default:
175 		return (NWAM_INVALID_ARG);
176 	}
177 	return (nwam_value_create(old->nwv_value_type, values,
178 	    old->nwv_value_numvalues, newp));
179 }
180 nwam_error_t
181 nwam_value_create_boolean_array(boolean_t *values, uint_t numvalues,
182     nwam_value_t *valuep)
183 {
184 	return (nwam_value_create(NWAM_VALUE_TYPE_BOOLEAN, values, numvalues,
185 	    valuep));
186 }
187 
188 nwam_error_t
189 nwam_value_create_boolean(boolean_t value, nwam_value_t *valuep)
190 {
191 	return (nwam_value_create_boolean_array(&value, 1, valuep));
192 }
193 
194 nwam_error_t
195 nwam_value_create_int64_array(int64_t *values, uint_t numvalues,
196     nwam_value_t *valuep)
197 {
198 	return (nwam_value_create(NWAM_VALUE_TYPE_INT64, values, numvalues,
199 	    valuep));
200 }
201 
202 nwam_error_t
203 nwam_value_create_int64(int64_t value, nwam_value_t *valuep)
204 {
205 	return (nwam_value_create_int64_array(&value, 1, valuep));
206 }
207 
208 nwam_error_t
209 nwam_value_create_uint64_array(uint64_t *values, uint_t numvalues,
210     nwam_value_t *valuep)
211 {
212 	return (nwam_value_create(NWAM_VALUE_TYPE_UINT64, values, numvalues,
213 	    valuep));
214 }
215 
216 nwam_error_t
217 nwam_value_create_uint64(uint64_t value, nwam_value_t *valuep)
218 {
219 	return (nwam_value_create_uint64_array(&value, 1, valuep));
220 }
221 
222 nwam_error_t
223 nwam_value_create_string_array(char **values, uint_t numvalues,
224     nwam_value_t *valuep)
225 {
226 	return (nwam_value_create(NWAM_VALUE_TYPE_STRING, values, numvalues,
227 	    valuep));
228 }
229 
230 nwam_error_t
231 nwam_value_create_string(char *value, nwam_value_t *valuep)
232 {
233 	return (nwam_value_create_string_array(&value, 1, valuep));
234 }
235 
236 nwam_error_t
237 nwam_value_get_boolean_array(nwam_value_t value, boolean_t **valuesp,
238     uint_t *numvaluesp)
239 {
240 	assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
241 
242 	*numvaluesp = value->nwv_value_numvalues;
243 	*valuesp = value->nwv_values.nwv_boolean;
244 	return (NWAM_SUCCESS);
245 }
246 
247 nwam_error_t
248 nwam_value_get_boolean(nwam_value_t value, boolean_t *valuep)
249 {
250 	uint_t numvalues;
251 	boolean_t *myvaluesp;
252 	nwam_error_t err;
253 
254 	err = nwam_value_get_boolean_array(value, &myvaluesp, &numvalues);
255 	if (err != NWAM_SUCCESS)
256 		return (err);
257 	if (numvalues != 1)
258 		return (NWAM_ENTITY_MULTIPLE_VALUES);
259 
260 	*valuep = myvaluesp[0];
261 	return (NWAM_SUCCESS);
262 }
263 
264 nwam_error_t
265 nwam_value_get_int64_array(nwam_value_t value, int64_t **valuesp,
266     uint_t *numvaluesp)
267 {
268 	assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
269 
270 	*numvaluesp = value->nwv_value_numvalues;
271 	*valuesp = value->nwv_values.nwv_int64;
272 	return (NWAM_SUCCESS);
273 }
274 
275 nwam_error_t
276 nwam_value_get_int64(nwam_value_t value, int64_t *valuep)
277 {
278 	uint_t numvalues;
279 	int64_t *myvaluesp;
280 	nwam_error_t err;
281 
282 	err = nwam_value_get_int64_array(value, &myvaluesp, &numvalues);
283 	if (err != NWAM_SUCCESS)
284 		return (err);
285 	if (numvalues != 1)
286 		return (NWAM_ENTITY_MULTIPLE_VALUES);
287 
288 	*valuep = myvaluesp[0];
289 	return (NWAM_SUCCESS);
290 }
291 
292 nwam_error_t
293 nwam_value_get_uint64_array(nwam_value_t value, uint64_t **valuesp,
294     uint_t *numvaluesp)
295 {
296 	assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
297 
298 	*numvaluesp = value->nwv_value_numvalues;
299 	*valuesp = value->nwv_values.nwv_uint64;
300 	return (NWAM_SUCCESS);
301 }
302 
303 nwam_error_t
304 nwam_value_get_uint64(nwam_value_t value, uint64_t *valuep)
305 {
306 	uint_t numvalues;
307 	uint64_t *myvaluesp;
308 	nwam_error_t err;
309 
310 	err = nwam_value_get_uint64_array(value, &myvaluesp, &numvalues);
311 	if (err != NWAM_SUCCESS)
312 		return (err);
313 	if (numvalues != 1)
314 		return (NWAM_ENTITY_MULTIPLE_VALUES);
315 
316 	*valuep = myvaluesp[0];
317 	return (NWAM_SUCCESS);
318 }
319 
320 nwam_error_t
321 nwam_value_get_string_array(nwam_value_t value, char ***valuesp,
322     uint_t *numvaluesp)
323 {
324 	assert(value != NULL && numvaluesp != NULL && valuesp != NULL);
325 
326 	*numvaluesp = value->nwv_value_numvalues;
327 	*valuesp = value->nwv_values.nwv_string;
328 	return (NWAM_SUCCESS);
329 }
330 
331 nwam_error_t
332 nwam_value_get_string(nwam_value_t value, char **valuep)
333 {
334 	uint_t numvalues;
335 	char **myvaluesp;
336 	nwam_error_t err;
337 
338 	err = nwam_value_get_string_array(value, &myvaluesp, &numvalues);
339 	if (err != NWAM_SUCCESS)
340 		return (err);
341 	if (numvalues != 1)
342 		return (NWAM_ENTITY_MULTIPLE_VALUES);
343 
344 	*valuep = myvaluesp[0];
345 	return (NWAM_SUCCESS);
346 }
347 
348 nwam_error_t
349 nwam_value_get_type(nwam_value_t value, nwam_value_type_t *typep)
350 {
351 	*typep = value->nwv_value_type;
352 	return (NWAM_SUCCESS);
353 }
354 
355 nwam_error_t
356 nwam_value_get_numvalues(nwam_value_t value, uint_t *numvaluesp)
357 {
358 	*numvaluesp = value->nwv_value_numvalues;
359 	return (NWAM_SUCCESS);
360 }
361 
362 /*
363  * Generic object data functions. We hide nvlist implementation
364  * from NCP, ENM and location implementations.
365  */
366 nwam_error_t
367 nwam_alloc_object_list(void *list)
368 {
369 	int nverr;
370 
371 	assert(list != NULL);
372 
373 	if ((nverr = nvlist_alloc((nvlist_t **)list, NV_UNIQUE_NAME, 0)) != 0)
374 		return (nwam_errno_to_nwam_error(nverr));
375 
376 	return (NWAM_SUCCESS);
377 }
378 
379 void
380 nwam_free_object_list(void *list)
381 {
382 	if (list != NULL)
383 		nvlist_free(list);
384 }
385 
386 nwam_error_t
387 nwam_dup_object_list(void *oldlist, void *newlist)
388 {
389 	int nverr;
390 
391 	assert(oldlist != NULL && newlist != NULL);
392 
393 	if ((nverr = nvlist_dup(oldlist, newlist, 0)) != 0)
394 		return (nwam_errno_to_nwam_error(nverr));
395 
396 	return (NWAM_SUCCESS);
397 }
398 
399 /* Add child object list to parent object list using property name childname */
400 nwam_error_t
401 nwam_object_list_add_object_list(void *parentlist, char *childname,
402     void *childlist)
403 {
404 	return (nwam_errno_to_nwam_error(nvlist_add_nvlist(parentlist,
405 	    childname, childlist)));
406 }
407 
408 /* Remove object list from parent object list */
409 nwam_error_t
410 nwam_object_list_remove_object_list(void *parentlist, char *childname)
411 {
412 	return (nwam_errno_to_nwam_error(nvlist_remove_all(parentlist,
413 	    childname)));
414 }
415 
416 /*
417  * Get next object list (nvlist) after lastname.  Used to walk NCUs, ENMs and
418  * locations, each of which is internally represented as an nvlist.
419  */
420 nwam_error_t
421 nwam_next_object_list(void *parentlist, char *lastname, char **childnamep,
422     void *childlistp)
423 {
424 	nvpair_t *last = NULL, *next;
425 	int nverr;
426 
427 	if (lastname != NULL) {
428 		if ((nverr = nvlist_lookup_nvpair(parentlist, lastname, &last))
429 		    != 0)
430 			return (nwam_errno_to_nwam_error(nverr));
431 	}
432 	if ((next = nvlist_next_nvpair(parentlist, last)) == NULL)
433 		return (NWAM_LIST_END);
434 
435 	*childnamep = nvpair_name(next);
436 
437 	if (nvpair_type(next) != DATA_TYPE_NVLIST)
438 		return (NWAM_ERROR_INTERNAL);
439 
440 	if ((nverr = nvpair_value_nvlist(next, childlistp)) != NWAM_SUCCESS)
441 		return (nwam_errno_to_nwam_error(nverr));
442 
443 	return (NWAM_SUCCESS);
444 }
445 
446 /*
447  * Pack nvlist into contiguous memory. If packed_listp is NULL, we just
448  * return the size of the memory needed to do so.
449  */
450 nwam_error_t
451 nwam_pack_object_list(void *list, char **packed_listp, size_t *packed_sizep)
452 {
453 	int nverr;
454 
455 	assert(list != NULL && packed_sizep != NULL);
456 
457 	if (packed_listp == NULL) {
458 		nverr = nvlist_size(list, packed_sizep, NV_ENCODE_XDR);
459 	} else {
460 		nverr = nvlist_pack(list, packed_listp, packed_sizep,
461 		    NV_ENCODE_XDR, 0);
462 	}
463 
464 	if (nverr != 0)
465 		return (nwam_errno_to_nwam_error(nverr));
466 
467 	return (NWAM_SUCCESS);
468 }
469 
470 nwam_error_t
471 nwam_unpack_object_list(char *packed_list, size_t packed_size,
472     void *list)
473 {
474 	int nverr;
475 
476 	assert(packed_list != NULL && list != NULL);
477 
478 	*((nvlist_t **)list) = NULL;
479 
480 	nverr = nvlist_unpack(packed_list, packed_size, (nvlist_t **)list, 0);
481 
482 	if (nverr != 0)
483 		return (nwam_errno_to_nwam_error(nverr));
484 
485 	return (NWAM_SUCCESS);
486 }
487 
488 /*
489  * Functions to walk, set and get properties in nvlist, translating
490  * between nwam_value_t and nvlist/nvpair representations.
491  */
492 nwam_error_t
493 nwam_next_object_prop(void *list, char *lastname, char **namep,
494     nwam_value_t *valuep)
495 {
496 	nvpair_t *last = NULL, *next;
497 	int nverr;
498 
499 	if (lastname != NULL) {
500 		if ((nverr = nvlist_lookup_nvpair(list, lastname, &last)) != 0)
501 			return (nwam_errno_to_nwam_error(nverr));
502 	}
503 	if ((next = nvlist_next_nvpair(list, last)) == NULL)
504 		return (NWAM_LIST_END);
505 
506 	*namep = nvpair_name(next);
507 
508 	return (nwam_get_prop_value(list, (const char *)*namep, valuep));
509 }
510 
511 nwam_error_t
512 nwam_get_prop_value(void *list, const char *name, nwam_value_t *valuep)
513 {
514 	nvpair_t *prop;
515 	nwam_error_t err;
516 	int nverr;
517 	boolean_t *valbool;
518 	int64_t *valint64;
519 	uint64_t *valuint64;
520 	char **valstr;
521 	uint_t numvalues;
522 
523 	assert(valuep != NULL);
524 
525 	*valuep = NULL;
526 
527 	if ((nverr = nvlist_lookup_nvpair(list, name, &prop)) != 0) {
528 		/* convert EINVAL to NOT_FOUND */
529 		if (nverr == EINVAL)
530 			return (NWAM_ENTITY_NOT_FOUND);
531 		return (nwam_errno_to_nwam_error(nverr));
532 	}
533 
534 	switch (nvpair_type(prop)) {
535 	case DATA_TYPE_BOOLEAN_ARRAY:
536 		if ((nverr = nvpair_value_boolean_array(prop,
537 		    &valbool, &numvalues)) != 0)
538 			return (nwam_errno_to_nwam_error(nverr));
539 		if ((err = nwam_value_create_boolean_array(valbool, numvalues,
540 		    valuep)) != NWAM_SUCCESS)
541 			return (err);
542 		break;
543 	case DATA_TYPE_INT64_ARRAY:
544 		if ((nverr = nvpair_value_int64_array(prop,
545 		    &valint64, &numvalues)) != 0)
546 			return (nwam_errno_to_nwam_error(nverr));
547 		if ((err = nwam_value_create_int64_array(valint64, numvalues,
548 		    valuep)) != NWAM_SUCCESS)
549 			return (err);
550 		break;
551 	case DATA_TYPE_UINT64_ARRAY:
552 		if ((nverr = nvpair_value_uint64_array(prop,
553 		    &valuint64, &numvalues)) != 0)
554 			return (nwam_errno_to_nwam_error(nverr));
555 		if ((err = nwam_value_create_uint64_array(valuint64, numvalues,
556 		    valuep)) != NWAM_SUCCESS)
557 			return (err);
558 		break;
559 	case DATA_TYPE_STRING_ARRAY:
560 		if ((nverr = nvpair_value_string_array(prop,
561 		    &valstr, &numvalues)) != 0)
562 			return (nwam_errno_to_nwam_error(nverr));
563 		if ((err = nwam_value_create_string_array(valstr, numvalues,
564 		    valuep)) != NWAM_SUCCESS)
565 			return (err);
566 		break;
567 	default:
568 		/* Should not happen */
569 		return (NWAM_ERROR_INTERNAL);
570 	}
571 	return (NWAM_SUCCESS);
572 }
573 
574 nwam_error_t
575 nwam_delete_prop(void *list, const char *name)
576 {
577 	int nverr;
578 
579 	if ((nverr = nvlist_remove_all(list, name)) != 0)
580 		return (nwam_errno_to_nwam_error(nverr));
581 	return (NWAM_SUCCESS);
582 }
583 
584 nwam_error_t
585 nwam_set_prop_value(void *list, const char *propname, nwam_value_t value)
586 {
587 	int nverr;
588 	nwam_error_t err;
589 	nwam_value_type_t type;
590 	uint_t numvalues;
591 	boolean_t *valbool;
592 	int64_t *valint64;
593 	uint64_t *valuint64;
594 	char **valstr;
595 
596 	assert(list != NULL && value != NULL);
597 
598 	if ((err = nwam_value_get_type(value, &type)) != NWAM_SUCCESS)
599 		return (err);
600 
601 	switch (type) {
602 	case NWAM_VALUE_TYPE_BOOLEAN:
603 		if ((err = nwam_value_get_boolean_array(value, &valbool,
604 		    &numvalues)) != NWAM_SUCCESS)
605 			return (err);
606 		if ((nverr = nvlist_add_boolean_array(list, propname,
607 		    valbool, numvalues)) != 0)
608 			return (nwam_errno_to_nwam_error(nverr));
609 		break;
610 	case NWAM_VALUE_TYPE_INT64:
611 		if ((err = nwam_value_get_int64_array(value, &valint64,
612 		    &numvalues)) != NWAM_SUCCESS)
613 			return (err);
614 		if ((nverr = nvlist_add_int64_array(list, propname,
615 		    valint64, numvalues)) != 0)
616 			return (nwam_errno_to_nwam_error(nverr));
617 		break;
618 	case NWAM_VALUE_TYPE_UINT64:
619 		if ((err = nwam_value_get_uint64_array(value, &valuint64,
620 		    &numvalues)) != NWAM_SUCCESS)
621 			return (err);
622 		if ((nverr = nvlist_add_uint64_array(list, propname,
623 		    valuint64, numvalues)) != 0)
624 			return (nwam_errno_to_nwam_error(nverr));
625 		break;
626 	case NWAM_VALUE_TYPE_STRING:
627 		if ((err = nwam_value_get_string_array(value, &valstr,
628 		    &numvalues)) != NWAM_SUCCESS)
629 			return (err);
630 		if ((nverr = nvlist_add_string_array(list, propname,
631 		    valstr, numvalues)) != 0)
632 			return (nwam_errno_to_nwam_error(nverr));
633 		break;
634 	default:
635 		return (NWAM_INVALID_ARG);
636 	}
637 
638 	return (NWAM_SUCCESS);
639 }
640 
641 /* Map uint64 values to their string counterparts */
642 
643 struct nwam_value_entry {
644 	const char	*value_string;
645 	uint64_t		value;
646 };
647 
648 struct nwam_value_entry prop_activation_mode_value_entries[] =
649 {
650 	{ NWAM_ACTIVATION_MODE_MANUAL_STRING, NWAM_ACTIVATION_MODE_MANUAL },
651 	{ NWAM_ACTIVATION_MODE_SYSTEM_STRING, NWAM_ACTIVATION_MODE_SYSTEM },
652 	{ NWAM_ACTIVATION_MODE_CONDITIONAL_ANY_STRING,
653 	NWAM_ACTIVATION_MODE_CONDITIONAL_ANY },
654 	{ NWAM_ACTIVATION_MODE_CONDITIONAL_ALL_STRING,
655 	NWAM_ACTIVATION_MODE_CONDITIONAL_ALL },
656 	{ NWAM_ACTIVATION_MODE_PRIORITIZED_STRING,
657 	NWAM_ACTIVATION_MODE_PRIORITIZED },
658 	{ NULL, 0 }
659 };
660 
661 struct nwam_value_entry ncu_prop_type_entries[] =
662 {
663 	{ NWAM_NCU_TYPE_LINK_STRING, NWAM_NCU_TYPE_LINK },
664 	{ NWAM_NCU_TYPE_INTERFACE_STRING, NWAM_NCU_TYPE_INTERFACE },
665 	{ NULL, 0 }
666 };
667 
668 struct nwam_value_entry ncu_prop_class_entries[] =
669 {
670 	{ NWAM_NCU_CLASS_PHYS_STRING, NWAM_NCU_CLASS_PHYS },
671 	{ NWAM_NCU_CLASS_IP_STRING, NWAM_NCU_CLASS_IP },
672 	{ NULL, 0 }
673 };
674 
675 struct nwam_value_entry ncu_prop_ip_version_entries[] =
676 {
677 	{ NWAM_IP_VERSION_IPV4_STRING, IPV4_VERSION },
678 	{ NWAM_IP_VERSION_IPV6_STRING, IPV6_VERSION },
679 	{ NULL, 0 }
680 };
681 
682 struct nwam_value_entry ncu_prop_ipv4_addrsrc_entries[] =
683 {
684 	{ NWAM_ADDRSRC_DHCP_STRING, NWAM_ADDRSRC_DHCP },
685 	{ NWAM_ADDRSRC_STATIC_STRING, NWAM_ADDRSRC_STATIC },
686 	{ NULL, 0 }
687 };
688 
689 struct nwam_value_entry ncu_prop_ipv6_addrsrc_entries[] =
690 {
691 	{ NWAM_ADDRSRC_DHCP_STRING, NWAM_ADDRSRC_DHCP },
692 	{ NWAM_ADDRSRC_STATIC_STRING, NWAM_ADDRSRC_STATIC },
693 	{ NWAM_ADDRSRC_AUTOCONF_STRING, NWAM_ADDRSRC_AUTOCONF },
694 	{ NULL, 0 }
695 };
696 
697 struct nwam_value_entry ncu_prop_priority_mode_entries[] =
698 {
699 	{ NWAM_PRIORITY_MODE_EXCLUSIVE_STRING, NWAM_PRIORITY_MODE_EXCLUSIVE },
700 	{ NWAM_PRIORITY_MODE_SHARED_STRING, NWAM_PRIORITY_MODE_SHARED },
701 	{ NWAM_PRIORITY_MODE_ALL_STRING, NWAM_PRIORITY_MODE_ALL },
702 	{ NULL, 0 }
703 };
704 
705 struct nwam_value_entry loc_prop_nameservices_entries[] =
706 {
707 	{ NWAM_NAMESERVICES_DNS_STRING, NWAM_NAMESERVICES_DNS },
708 	{ NWAM_NAMESERVICES_FILES_STRING, NWAM_NAMESERVICES_FILES },
709 	{ NWAM_NAMESERVICES_NIS_STRING, NWAM_NAMESERVICES_NIS },
710 	{ NWAM_NAMESERVICES_LDAP_STRING, NWAM_NAMESERVICES_LDAP },
711 	{ NULL, 0 }
712 };
713 
714 struct nwam_value_entry loc_prop_nameservice_configsrc_entries[] =
715 {
716 	{ NWAM_CONFIGSRC_MANUAL_STRING, NWAM_CONFIGSRC_MANUAL },
717 	{ NWAM_CONFIGSRC_DHCP_STRING, NWAM_CONFIGSRC_DHCP },
718 	{ NULL, 0 }
719 };
720 
721 struct nwam_value_entry known_wlan_prop_security_mode_entries[] =
722 {
723 	{ "none", DLADM_WLAN_SECMODE_NONE },
724 	{ "wep", DLADM_WLAN_SECMODE_WEP },
725 	{ "wpa", DLADM_WLAN_SECMODE_WPA },
726 	{ NULL, 0 }
727 };
728 
729 struct nwam_prop_value_entry {
730 	const char		*prop_name;
731 	struct nwam_value_entry	*value_entries;
732 } prop_value_entry_table[] =
733 {
734 	{ NWAM_NCU_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
735 	{ NWAM_NCU_PROP_TYPE, ncu_prop_type_entries },
736 	{ NWAM_NCU_PROP_CLASS, ncu_prop_class_entries },
737 	{ NWAM_NCU_PROP_IP_VERSION, ncu_prop_ip_version_entries },
738 	{ NWAM_NCU_PROP_IPV4_ADDRSRC, ncu_prop_ipv4_addrsrc_entries },
739 	{ NWAM_NCU_PROP_IPV6_ADDRSRC, ncu_prop_ipv6_addrsrc_entries },
740 	{ NWAM_NCU_PROP_PRIORITY_MODE, ncu_prop_priority_mode_entries },
741 	{ NWAM_ENM_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
742 	{ NWAM_LOC_PROP_ACTIVATION_MODE, prop_activation_mode_value_entries },
743 	{ NWAM_LOC_PROP_NAMESERVICES, loc_prop_nameservices_entries },
744 	{ NWAM_LOC_PROP_DNS_NAMESERVICE_CONFIGSRC,
745 	    loc_prop_nameservice_configsrc_entries },
746 	{ NWAM_LOC_PROP_NIS_NAMESERVICE_CONFIGSRC,
747 	    loc_prop_nameservice_configsrc_entries },
748 	{ NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
749 	    loc_prop_nameservice_configsrc_entries },
750 	{ NWAM_KNOWN_WLAN_PROP_SECURITY_MODE,
751 	    known_wlan_prop_security_mode_entries },
752 	{ NULL, NULL }
753 };
754 
755 /*
756  * Convert uint64 values for property propname into a string representing
757  * that value. Used by enum values.
758  */
759 nwam_error_t
760 nwam_uint64_get_value_string(const char *propname, uint64_t val,
761     const char **valstrp)
762 {
763 	int i, j;
764 	int max = 0; /* largest enum value seen so far */
765 	struct nwam_value_entry *value_entries;
766 
767 	assert(propname != NULL && valstrp != NULL);
768 
769 	for (i = 0; prop_value_entry_table[i].prop_name != NULL; i++) {
770 		if (strcmp(prop_value_entry_table[i].prop_name, propname) != 0)
771 			continue;
772 
773 		value_entries = prop_value_entry_table[i].value_entries;
774 
775 		for (j = 0; value_entries[j].value_string != NULL; j++) {
776 			if (value_entries[j].value == val) {
777 				*valstrp = value_entries[j].value_string;
778 				return (NWAM_SUCCESS);
779 			}
780 			max = value_entries[j].value > max ?
781 			    value_entries[j].value : max;
782 		}
783 		/*
784 		 * If trying to get the string for an enum value that doesn't
785 		 * exist, return NWAM_LIST_END.  Otherwise, the input enum
786 		 * value doesn't exist for the given property.
787 		 */
788 		if (val > max)
789 			return (NWAM_LIST_END);
790 		else
791 			return (NWAM_ENTITY_INVALID_VALUE);
792 	}
793 	return (NWAM_INVALID_ARG);
794 }
795 
796 /*
797  * Convert string to appropriate uint64 value.
798  */
799 nwam_error_t
800 nwam_value_string_get_uint64(const char *propname, const char *valstr,
801     uint64_t *valp)
802 {
803 	int i, j;
804 	struct nwam_value_entry *value_entries;
805 
806 	assert(propname != NULL && valstr != NULL && valp != NULL);
807 
808 	for (i = 0; prop_value_entry_table[i].prop_name != NULL; i++) {
809 		if (strcmp(prop_value_entry_table[i].prop_name, propname) != 0)
810 			continue;
811 
812 		value_entries = prop_value_entry_table[i].value_entries;
813 
814 		for (j = 0; value_entries[j].value_string != NULL; j++) {
815 			if (strcasecmp(value_entries[j].value_string, valstr)
816 			    == 0) {
817 				*valp = value_entries[j].value;
818 				return (NWAM_SUCCESS);
819 			}
820 		}
821 		return (NWAM_ENTITY_INVALID_VALUE);
822 	}
823 	return (NWAM_INVALID_ARG);
824 }
825 
826 /* Conditional activation functions */
827 
828 nwam_error_t
829 nwam_condition_to_condition_string(nwam_condition_object_type_t object_type,
830     nwam_condition_t condition, const char *object_name, char **stringp)
831 {
832 	char *object_type_string, *condition_string;
833 	char *string;
834 
835 	assert(stringp != NULL);
836 
837 	*stringp = NULL;
838 
839 	switch (object_type) {
840 	case NWAM_CONDITION_OBJECT_TYPE_NCP:
841 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_NCP_STRING;
842 		break;
843 	case NWAM_CONDITION_OBJECT_TYPE_NCU:
844 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_NCU_STRING;
845 		break;
846 	case NWAM_CONDITION_OBJECT_TYPE_ENM:
847 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_ENM_STRING;
848 		break;
849 	case NWAM_CONDITION_OBJECT_TYPE_LOC:
850 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_LOC_STRING;
851 		break;
852 	case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
853 		object_type_string =
854 		    NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS_STRING;
855 		break;
856 	case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
857 		object_type_string =
858 		    NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN_STRING;
859 		break;
860 	case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
861 		object_type_string =
862 		    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING;
863 		break;
864 	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
865 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING;
866 		break;
867 	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
868 		object_type_string = NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING;
869 		break;
870 	default:
871 		return (NWAM_INVALID_ARG);
872 
873 	}
874 	switch (condition) {
875 	case NWAM_CONDITION_IS:
876 		condition_string = NWAM_CONDITION_IS_STRING;
877 		break;
878 	case NWAM_CONDITION_IS_NOT:
879 		condition_string = NWAM_CONDITION_IS_NOT_STRING;
880 		break;
881 	case NWAM_CONDITION_CONTAINS:
882 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
883 		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
884 		    object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
885 			return (NWAM_INVALID_ARG);
886 		condition_string = NWAM_CONDITION_CONTAINS_STRING;
887 		break;
888 	case NWAM_CONDITION_DOES_NOT_CONTAIN:
889 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
890 		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
891 		    object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
892 			return (NWAM_INVALID_ARG);
893 
894 		condition_string = NWAM_CONDITION_DOES_NOT_CONTAIN_STRING;
895 		break;
896 	case NWAM_CONDITION_IS_IN_RANGE:
897 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS)
898 			return (NWAM_INVALID_ARG);
899 		condition_string = NWAM_CONDITION_IS_IN_RANGE_STRING;
900 		break;
901 	case NWAM_CONDITION_IS_NOT_IN_RANGE:
902 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS)
903 			return (NWAM_INVALID_ARG);
904 		condition_string = NWAM_CONDITION_IS_NOT_IN_RANGE_STRING;
905 		break;
906 	default:
907 		return (NWAM_INVALID_ARG);
908 		break;
909 	}
910 	if ((string = malloc(NWAM_MAX_VALUE_LEN)) == NULL)
911 		return (NWAM_NO_MEMORY);
912 	switch (object_type) {
913 	case NWAM_CONDITION_OBJECT_TYPE_NCP:
914 	case NWAM_CONDITION_OBJECT_TYPE_NCU:
915 	case NWAM_CONDITION_OBJECT_TYPE_ENM:
916 	case NWAM_CONDITION_OBJECT_TYPE_LOC:
917 		(void) snprintf(string, NWAM_MAX_VALUE_LEN,
918 		    "%s %s %s active", object_type_string,
919 		    object_name, condition_string);
920 		*stringp = string;
921 		break;
922 
923 	case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
924 	case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
925 	case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
926 	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
927 	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
928 		(void) snprintf(string, NWAM_MAX_VALUE_LEN,
929 		    "%s %s %s", object_type_string,
930 		    condition_string, object_name);
931 		*stringp = string;
932 		break;
933 
934 	default:
935 		free(string);
936 		return (NWAM_INVALID_ARG);
937 
938 	}
939 	return (NWAM_SUCCESS);
940 }
941 
942 nwam_error_t
943 nwam_condition_string_to_condition(const char *string,
944     nwam_condition_object_type_t *object_typep,
945     nwam_condition_t *conditionp, char **object_namep)
946 {
947 	char *copy, *lasts;
948 	char *object_type_string, *object_name;
949 	char *condition_string, *active_string;
950 
951 	assert(string != NULL && object_typep != NULL && conditionp != NULL &&
952 	    object_namep != NULL);
953 
954 	if ((copy = strdup(string)) == NULL)
955 		return (NWAM_NO_MEMORY);
956 
957 	if ((object_type_string = strtok_r(copy, " \t", &lasts)) == NULL) {
958 		free(copy);
959 		return (NWAM_INVALID_ARG);
960 	}
961 
962 	if (strcmp(object_type_string, NWAM_CONDITION_OBJECT_TYPE_NCP_STRING)
963 	    == 0)
964 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_NCP;
965 	else if (strcmp(object_type_string,
966 	    NWAM_CONDITION_OBJECT_TYPE_NCU_STRING) == 0)
967 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_NCU;
968 	else if (strcmp(object_type_string,
969 	    NWAM_CONDITION_OBJECT_TYPE_ENM_STRING) == 0)
970 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_ENM;
971 	else if (strcmp(object_type_string,
972 	    NWAM_CONDITION_OBJECT_TYPE_LOC_STRING) == 0)
973 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_LOC;
974 	else if (strcmp(object_type_string,
975 	    NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS_STRING) == 0)
976 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS;
977 	else if (strcmp(object_type_string,
978 	    NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN_STRING) == 0)
979 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN;
980 	else if (strcmp(object_type_string,
981 	    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING) == 0)
982 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN;
983 	else if (strcmp(object_type_string,
984 	    NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING) == 0)
985 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_ESSID;
986 	else if (strcmp(object_type_string,
987 	    NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING) == 0)
988 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_BSSID;
989 	else {
990 		free(copy);
991 		return (NWAM_INVALID_ARG);
992 	}
993 
994 	if (*object_typep == NWAM_CONDITION_OBJECT_TYPE_NCP ||
995 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_NCU ||
996 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_ENM ||
997 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_LOC) {
998 		if ((object_name = strtok_r(NULL, " \t", &lasts)) == NULL) {
999 			free(copy);
1000 			return (NWAM_INVALID_ARG);
1001 		}
1002 		if ((*object_namep = strdup(object_name)) == NULL) {
1003 			free(copy);
1004 			return (NWAM_NO_MEMORY);
1005 		}
1006 
1007 	}
1008 
1009 	if ((condition_string = strtok_r(NULL, " \t", &lasts)) == NULL) {
1010 		free(copy);
1011 		if (*object_namep != NULL)
1012 			free(*object_namep);
1013 		return (NWAM_INVALID_ARG);
1014 	}
1015 	if (strcmp(condition_string, NWAM_CONDITION_IS_STRING) == 0)
1016 		*conditionp = NWAM_CONDITION_IS;
1017 	else if (strcmp(condition_string, NWAM_CONDITION_IS_NOT_STRING) == 0)
1018 		*conditionp = NWAM_CONDITION_IS_NOT;
1019 	else if (strcmp(condition_string, NWAM_CONDITION_CONTAINS_STRING) == 0)
1020 		*conditionp = NWAM_CONDITION_CONTAINS;
1021 	else if (strcmp(condition_string,
1022 	    NWAM_CONDITION_DOES_NOT_CONTAIN_STRING) == 0)
1023 		*conditionp = NWAM_CONDITION_DOES_NOT_CONTAIN;
1024 	else if (strcmp(condition_string,
1025 	    NWAM_CONDITION_IS_IN_RANGE_STRING) == 0)
1026 		*conditionp = NWAM_CONDITION_IS_IN_RANGE;
1027 	else if (strcmp(condition_string,
1028 	    NWAM_CONDITION_IS_NOT_IN_RANGE_STRING) == 0)
1029 		*conditionp = NWAM_CONDITION_IS_NOT_IN_RANGE;
1030 	else {
1031 		free(copy);
1032 		if (*object_namep != NULL)
1033 			free(*object_namep);
1034 		return (NWAM_INVALID_ARG);
1035 	}
1036 
1037 	if (*object_typep == NWAM_CONDITION_OBJECT_TYPE_NCP ||
1038 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_NCU ||
1039 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_ENM ||
1040 	    *object_typep == NWAM_CONDITION_OBJECT_TYPE_LOC) {
1041 		if ((*conditionp != NWAM_CONDITION_IS &&
1042 		    *conditionp != NWAM_CONDITION_IS_NOT) ||
1043 		    (active_string = strtok_r(NULL, " \t", &lasts)) == NULL ||
1044 		    strcmp(active_string, NWAM_CONDITION_ACTIVE_STRING) != 0) {
1045 			free(copy);
1046 			free(*object_namep);
1047 			return (NWAM_INVALID_ARG);
1048 		}
1049 	} else {
1050 		switch (*conditionp) {
1051 		case NWAM_CONDITION_CONTAINS:
1052 		case NWAM_CONDITION_DOES_NOT_CONTAIN:
1053 			if (*object_typep !=
1054 			    NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
1055 			    *object_typep !=
1056 			    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
1057 			    *object_typep != NWAM_CONDITION_OBJECT_TYPE_ESSID) {
1058 				free(copy);
1059 				free(*object_namep);
1060 				return (NWAM_INVALID_ARG);
1061 			}
1062 			break;
1063 		case NWAM_CONDITION_IS_IN_RANGE:
1064 		case NWAM_CONDITION_IS_NOT_IN_RANGE:
1065 			if (*object_typep !=
1066 			    NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS) {
1067 				free(copy);
1068 				free(*object_namep);
1069 				return (NWAM_INVALID_ARG);
1070 			}
1071 			break;
1072 		}
1073 
1074 		if ((object_name = strtok_r(NULL, " \t", &lasts)) == NULL) {
1075 			free(copy);
1076 			free(*object_namep);
1077 			return (NWAM_INVALID_ARG);
1078 		}
1079 		if ((*object_namep = strdup(object_name)) == NULL) {
1080 			free(copy);
1081 			free(*object_namep);
1082 			return (NWAM_NO_MEMORY);
1083 		}
1084 	}
1085 
1086 	free(copy);
1087 	return (NWAM_SUCCESS);
1088 }
1089 
1090 nwam_error_t
1091 nwam_condition_rate(nwam_condition_object_type_t object_type,
1092     nwam_condition_t condition, uint64_t *ratep)
1093 {
1094 	assert(ratep != NULL);
1095 
1096 	*ratep = 0;
1097 
1098 	switch (object_type) {
1099 	case NWAM_CONDITION_OBJECT_TYPE_NCP:
1100 	case NWAM_CONDITION_OBJECT_TYPE_NCU:
1101 	case NWAM_CONDITION_OBJECT_TYPE_ENM:
1102 	case NWAM_CONDITION_OBJECT_TYPE_LOC:
1103 		(*ratep)++;
1104 		/* FALLTHRU */
1105 	case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
1106 		(*ratep)++;
1107 		/* FALLTHRU */
1108 	case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
1109 		(*ratep)++;
1110 		/* FALLTHRU */
1111 	case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
1112 		(*ratep)++;
1113 		/* FALLTHRU */
1114 	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
1115 		(*ratep)++;
1116 		/* FALLTHRU */
1117 	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
1118 		(*ratep)++;
1119 		break;
1120 	default:
1121 		return (NWAM_INVALID_ARG);
1122 	}
1123 
1124 	switch (condition) {
1125 	case NWAM_CONDITION_IS:
1126 		(*ratep)++;
1127 		/* FALLTHRU */
1128 	case NWAM_CONDITION_CONTAINS:
1129 	case NWAM_CONDITION_IS_IN_RANGE:
1130 		(*ratep)++;
1131 		/* FALLTHRU */
1132 	case NWAM_CONDITION_DOES_NOT_CONTAIN:
1133 	case NWAM_CONDITION_IS_NOT_IN_RANGE:
1134 		(*ratep)++;
1135 		/* FALLTHRU */
1136 	case NWAM_CONDITION_IS_NOT:
1137 		(*ratep)++;
1138 		break;
1139 	default:
1140 		return (NWAM_INVALID_ARG);
1141 	}
1142 	return (NWAM_SUCCESS);
1143 }
1144