5525 Update hwdata - 20150111
[illumos-gate.git] / usr / src / lib / libnwam / common / libnwam_object.c
blob4d336dbcf1a044eec3d652874d47b62eea78f3c6
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <strings.h>
30 #include <string.h>
32 #include "libnwam_impl.h"
33 #include <libintl.h>
34 #include <libnwam.h>
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.
45 nwam_error_t
46 nwam_handle_create(nwam_object_type_t type, const char *name,
47 struct nwam_handle **hpp)
50 assert(name != NULL && hpp != NULL);
52 if (strnlen(name, NWAM_MAX_NAME_LEN) > NWAM_MAX_NAME_LEN) {
53 *hpp = NULL;
54 return (NWAM_INVALID_ARG);
57 if ((*hpp = calloc(1, sizeof (struct nwam_handle))) == NULL)
58 return (NWAM_NO_MEMORY);
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;
65 return (NWAM_SUCCESS);
69 * Read object of specified type from dbname.
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)
75 nwam_error_t err;
76 char dbname_copy[MAXPATHLEN];
78 assert(name != NULL && hpp != NULL);
80 if (dbname != NULL)
81 (void) strlcpy(dbname_copy, dbname, sizeof (dbname_copy));
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);
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);
96 if (type == NWAM_OBJECT_TYPE_NCP && dbname != NULL) {
97 char *ncpname;
100 * dbname_copy may have been changed due to case-insensitive
101 * match against the actual NCP configuration file.
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);
111 (*hpp)->nwh_committed = B_TRUE;
113 return (NWAM_SUCCESS);
117 * Create simply creates the handle - the object-specific function must
118 * then fill in property values.
120 nwam_error_t
121 nwam_create(nwam_object_type_t type, const char *dbname, const char *name,
122 struct nwam_handle **hpp)
124 struct nwam_handle *hp;
126 assert(hpp != NULL && name != NULL);
128 if (nwam_read(type, dbname, name, 0, &hp) == NWAM_SUCCESS) {
129 nwam_free(hp);
130 return (NWAM_ENTITY_EXISTS);
132 /* Create handle */
133 return (nwam_handle_create(type, name, hpp));
136 nwam_error_t
137 nwam_get_name(struct nwam_handle *hp, char **namep)
139 assert(hp != NULL && namep != NULL);
141 if ((*namep = strdup(hp->nwh_name)) == NULL) {
142 *namep = NULL;
143 return (NWAM_NO_MEMORY);
145 return (NWAM_SUCCESS);
148 nwam_error_t
149 nwam_set_name(struct nwam_handle *hp, const char *name)
151 assert(hp != NULL && name != NULL);
153 if (hp->nwh_committed)
154 return (NWAM_ENTITY_READ_ONLY);
156 if (strlen(name) >= sizeof (hp->nwh_name))
157 return (NWAM_INVALID_ARG);
159 (void) strcpy(hp->nwh_name, name);
161 return (NWAM_SUCCESS);
164 /* Compare object names c1 and c2 using strcasecmp() */
165 static int
166 name_cmp(const void *c1, const void *c2)
168 nwam_ncu_type_t t1, t2;
169 char *n1, *n2;
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);
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;
187 return (ret);
190 return (strcasecmp(*(const char **)c1, *(const char **)c2));
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.
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 *))
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;
213 assert(cb != NULL);
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.
223 if ((err = nwam_read_object_from_backend((char *)dbname, NULL, flags,
224 &objlist)) != NWAM_SUCCESS) {
225 if (err == NWAM_ENTITY_NOT_FOUND) {
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.
231 return (NWAM_SUCCESS);
233 return (err);
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);
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);
248 /* sort the object names alphabetically */
249 qsort(object_names, num_objects, sizeof (char *), name_cmp);
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);
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);
271 nwam_free(hp);
273 nwam_value_free(value);
275 if (retp != NULL)
276 *retp = ret;
277 return (err);
280 void
281 nwam_free(struct nwam_handle *hp)
283 if (hp != NULL) {
284 if (hp->nwh_data != NULL)
285 nwam_free_object_list(hp->nwh_data);
286 free(hp);
291 * Copy object represented by oldhp to an object newname, all in container
292 * dbname.
294 nwam_error_t
295 nwam_copy(const char *dbname, struct nwam_handle *oldhp, const char *newname,
296 struct nwam_handle **newhpp)
298 nwam_error_t err;
299 struct nwam_handle *hp;
301 assert(oldhp != NULL && newname != NULL && newhpp != NULL);
303 if (nwam_read(oldhp->nwh_object_type, dbname, newname, 0, &hp)
304 == NWAM_SUCCESS) {
305 nwam_free(hp);
306 return (NWAM_ENTITY_EXISTS);
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);
319 return (NWAM_SUCCESS);
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)
328 char *lastpropname = NULL, *propname;
329 nwam_value_t value;
330 nwam_error_t err;
331 int ret = 0;
333 assert(hp != NULL && hp->nwh_data != NULL && cb != NULL);
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) {
340 ret = cb(propname, value, data);
341 if (ret != 0)
342 err = NWAM_WALK_HALTED;
344 /* Free value */
345 nwam_value_free(value);
347 if (err != NWAM_SUCCESS)
348 break;
350 lastpropname = propname;
353 if (retp != NULL)
354 *retp = ret;
355 if (err == NWAM_SUCCESS || err == NWAM_LIST_END)
356 return (NWAM_SUCCESS);
357 return (err);
361 * Note that prior to calling the generic commit function, object-specific
362 * validation should be carried out.
364 nwam_error_t
365 nwam_commit(const char *dbname, struct nwam_handle *hp, uint64_t flags)
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;
373 assert(hp != NULL);
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).
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);
387 is_ncu = (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU);
390 * Does object already exist? If not, action is ADD, otherwise REFRESH.
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;
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);
413 hp->nwh_committed = B_TRUE;
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.
419 if (is_ncu) {
420 char *ncpname;
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);
427 } else {
428 (void) nwam_request_action(hp->nwh_object_type, hp->nwh_name,
429 NULL, action);
431 return (NWAM_SUCCESS);
434 static boolean_t
435 nwam_is_active(struct nwam_handle *hp)
437 nwam_state_t state;
438 nwam_aux_state_t aux;
440 return ((nwam_get_state(NULL, hp, &state, &aux) == NWAM_SUCCESS &&
441 state == NWAM_STATE_ONLINE));
444 nwam_error_t
445 nwam_destroy(const char *dbname, struct nwam_handle *hp, uint64_t flags)
447 nwam_error_t err;
448 char *name;
449 boolean_t is_ncp, is_ncu;
451 assert(hp != NULL);
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);
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;
464 /* Check if object is active */
465 if (!is_ncp && !is_ncu && nwam_is_active(hp))
466 return (NWAM_ENTITY_IN_USE);
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);
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.
476 if (is_ncu) {
477 char *ncpname;
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);
484 } else {
485 (void) nwam_request_action(hp->nwh_object_type, name, NULL,
486 NWAM_ACTION_DESTROY);
489 if ((err == NWAM_SUCCESS) && !(flags & NWAM_FLAG_DO_NOT_FREE))
490 nwam_free(hp);
492 return (err);
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.
500 nwam_error_t
501 nwam_enable(const char *parent, struct nwam_handle *hp)
503 return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
504 parent, NWAM_ACTION_ENABLE));
507 nwam_error_t
508 nwam_disable(const char *parent, struct nwam_handle *hp)
510 return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
511 parent, NWAM_ACTION_DISABLE));
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)
518 return (nwam_request_state(hp->nwh_object_type, hp->nwh_name, parent,
519 statep, auxp));
522 struct nwam_prop_table_entry *
523 nwam_get_prop_table_entry(struct nwam_prop_table table, const char *propname)
525 struct nwam_prop_table_entry *cur = table.entries;
526 struct nwam_prop_table_entry *end = cur + table.num_entries;
528 assert(propname != NULL);
530 for (; cur < end; cur++) {
531 if (strcmp(propname, cur->prop_name) == 0)
532 return (cur);
534 return (NULL);
537 nwam_error_t
538 nwam_get_prop_description(struct nwam_prop_table table, const char *propname,
539 const char **descriptionp)
541 struct nwam_prop_table_entry *pte;
543 assert(propname != NULL && descriptionp != NULL);
545 if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL) {
546 *descriptionp = NULL;
547 return (NWAM_INVALID_ARG);
550 *descriptionp = dgettext(TEXT_DOMAIN, pte->prop_description);
551 return (NWAM_SUCCESS);
554 nwam_error_t
555 nwam_get_prop_type(struct nwam_prop_table table, const char *propname,
556 nwam_value_type_t *typep)
558 struct nwam_prop_table_entry *pte;
560 assert(propname != NULL && typep != NULL);
562 if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
563 return (NWAM_INVALID_ARG);
565 *typep = pte->prop_type;
567 return (NWAM_SUCCESS);
570 nwam_error_t
571 nwam_prop_multivalued(struct nwam_prop_table table, const char *propname,
572 boolean_t *multip)
574 struct nwam_prop_table_entry *pte;
576 assert(propname != NULL && multip != NULL);
578 if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
579 return (NWAM_INVALID_ARG);
581 if (pte->prop_max_numvalues > 1)
582 *multip = B_TRUE;
583 else
584 *multip = B_FALSE;
586 return (NWAM_SUCCESS);
589 nwam_error_t
590 nwam_prop_read_only(struct nwam_prop_table table, const char *propname,
591 boolean_t *readp)
593 struct nwam_prop_table_entry *pte;
595 assert(propname != NULL && readp != NULL);
597 if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
598 return (NWAM_INVALID_ARG);
600 *readp = (pte->prop_is_readonly && !nwam_uid_is_special());
602 return (NWAM_SUCCESS);
606 * Structure used to pass in prop table and errprop string pointer to internal
607 * validate function.
609 struct validate_internal_arg {
610 struct nwam_prop_table table;
611 const char **errpropp;
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.
620 static int
621 nwam_validate_prop_internal(const char *propname, nwam_value_t value,
622 void *arg)
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;
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);
640 if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
641 return (NWAM_INVALID_ARG);
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);
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);
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);
672 return (NWAM_SUCCESS);
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)
679 struct validate_internal_arg via;
681 assert(hp != NULL && propname != NULL);
683 via.table = table;
684 via.errpropp = NULL;
686 return ((nwam_error_t)nwam_validate_prop_internal(propname,
687 value, &via));
690 nwam_error_t
691 nwam_validate(struct nwam_prop_table table, struct nwam_handle *hp,
692 const char **errpropp)
694 struct validate_internal_arg via;
695 nwam_error_t err1, err2;
697 assert(hp != NULL);
699 via.table = table;
700 via.errpropp = errpropp;
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);
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.
715 * Caller needs to free prop_list.
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)
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;
726 assert(prop_list != NULL && numvalues != NULL);
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);
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;
741 *numvalues = i;
742 *prop_list = list;
743 return (NWAM_SUCCESS);