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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
32 #include "libnwam_impl.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.
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
) {
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.
72 nwam_read(nwam_object_type_t type
, const char *dbname
, const char *name
,
73 uint64_t flags
, struct nwam_handle
**hpp
)
76 char dbname_copy
[MAXPATHLEN
];
78 assert(name
!= NULL
&& hpp
!= NULL
);
81 (void) strlcpy(dbname_copy
, dbname
, sizeof (dbname_copy
));
83 if ((err
= nwam_valid_flags(flags
, NWAM_FLAG_BLOCKING
)) != NWAM_SUCCESS
)
85 if ((err
= nwam_handle_create(type
, name
, hpp
)) != NWAM_SUCCESS
)
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
) {
96 if (type
== NWAM_OBJECT_TYPE_NCP
&& dbname
!= NULL
) {
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
)
105 (void) strlcpy((*hpp
)->nwh_name
, ncpname
,
106 sizeof ((*hpp
)->nwh_name
));
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.
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
) {
130 return (NWAM_ENTITY_EXISTS
);
133 return (nwam_handle_create(type
, name
, hpp
));
137 nwam_get_name(struct nwam_handle
*hp
, char **namep
)
139 assert(hp
!= NULL
&& namep
!= NULL
);
141 if ((*namep
= strdup(hp
->nwh_name
)) == NULL
) {
143 return (NWAM_NO_MEMORY
);
145 return (NWAM_SUCCESS
);
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() */
166 name_cmp(const void *c1
, const void *c2
)
168 nwam_ncu_type_t t1
, t2
;
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
)
174 nwam_ncu_typed_name_to_name(*(const char **)c2
, &t2
, &n2
)
176 int ret
= strcasecmp(n1
, n2
);
180 /* For NCUs with the same name, compare their types */
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.
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 *))
208 uint_t i
, num_objects
= 0;
209 struct nwam_handle
*hp
;
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
);
236 if ((err
= nwam_get_prop_value(objlist
, NWAM_OBJECT_NAMES_STRING
,
237 &value
)) != NWAM_SUCCESS
) {
238 nwam_free_object_list(objlist
);
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
);
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
)
257 if (err
!= NWAM_SUCCESS
) {
258 nwam_value_free(value
);
261 if ((selectcb
== NULL
) || (selectcb(hp
, flags
, data
) == 0)) {
265 nwam_value_free(value
);
268 return (NWAM_WALK_HALTED
);
273 nwam_value_free(value
);
281 nwam_free(struct nwam_handle
*hp
)
284 if (hp
->nwh_data
!= NULL
)
285 nwam_free_object_list(hp
->nwh_data
);
291 * Copy object represented by oldhp to an object newname, all in container
295 nwam_copy(const char *dbname
, struct nwam_handle
*oldhp
, const char *newname
,
296 struct nwam_handle
**newhpp
)
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
)
306 return (NWAM_ENTITY_EXISTS
);
309 if ((err
= nwam_handle_create(oldhp
->nwh_object_type
, newname
, newhpp
))
312 if ((err
= nwam_dup_object_list(oldhp
->nwh_data
,
313 &((*newhpp
)->nwh_data
))) != NWAM_SUCCESS
) {
319 return (NWAM_SUCCESS
);
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
;
333 assert(hp
!= NULL
&& hp
->nwh_data
!= NULL
&& cb
!= NULL
);
335 if ((err
= nwam_valid_flags(flags
, 0)) != NWAM_SUCCESS
)
337 while ((err
= nwam_next_object_prop(hp
->nwh_data
, lastpropname
,
338 &propname
, &value
)) == NWAM_SUCCESS
) {
340 ret
= cb(propname
, value
, data
);
342 err
= NWAM_WALK_HALTED
;
345 nwam_value_free(value
);
347 if (err
!= NWAM_SUCCESS
)
350 lastpropname
= propname
;
355 if (err
== NWAM_SUCCESS
|| err
== NWAM_LIST_END
)
356 return (NWAM_SUCCESS
);
361 * Note that prior to calling the generic commit function, object-specific
362 * validation should be carried out.
365 nwam_commit(const char *dbname
, struct nwam_handle
*hp
, uint64_t flags
)
368 uint64_t iflags
= flags
;
370 struct nwam_handle
*testhp
;
371 nwam_action_t action
;
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
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
)))
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,
394 case NWAM_ENTITY_NOT_FOUND
:
395 action
= NWAM_ACTION_ADD
;
399 if (hp
->nwh_object_type
== NWAM_OBJECT_TYPE_NCP
)
400 return (NWAM_ENTITY_EXISTS
);
403 action
= NWAM_ACTION_REFRESH
;
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
)
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.
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
);
428 (void) nwam_request_action(hp
->nwh_object_type
, hp
->nwh_name
,
431 return (NWAM_SUCCESS
);
435 nwam_is_active(struct nwam_handle
*hp
)
438 nwam_aux_state_t aux
;
440 return ((nwam_get_state(NULL
, hp
, &state
, &aux
) == NWAM_SUCCESS
&&
441 state
== NWAM_STATE_ONLINE
));
445 nwam_destroy(const char *dbname
, struct nwam_handle
*hp
, uint64_t flags
)
449 boolean_t is_ncp
, is_ncu
;
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
)
460 is_ncp
= hp
->nwh_object_type
== NWAM_OBJECT_TYPE_NCP
;
461 is_ncu
= hp
->nwh_object_type
== NWAM_OBJECT_TYPE_NCU
;
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.
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
);
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
))
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.
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
));
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
));
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
,
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)
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
);
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
);
571 nwam_prop_multivalued(struct nwam_prop_table table
, const char *propname
,
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)
586 return (NWAM_SUCCESS
);
590 nwam_prop_read_only(struct nwam_prop_table table
, const char *propname
,
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
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)
621 nwam_validate_prop_internal(const char *propname
, nwam_value_t value
,
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
;
629 nwam_value_type_t type
;
633 if ((err
= nwam_value_get_numvalues(value
, &numvalues
))
635 (err
= nwam_value_get_type(value
, &type
)) != NWAM_SUCCESS
) {
636 if (errpropp
!= NULL
)
637 *errpropp
= propname
;
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
;
649 return (NWAM_ENTITY_NO_VALUE
);
651 return (NWAM_ENTITY_INVALID_VALUE
);
653 /* Ensure type matches */
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
;
672 return (NWAM_SUCCESS
);
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
);
686 return ((nwam_error_t
)nwam_validate_prop_internal(propname
,
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
;
700 via
.errpropp
= errpropp
;
702 err1
= nwam_walk_props(hp
, nwam_validate_prop_internal
, &via
,
704 if (err1
!= NWAM_SUCCESS
)
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.
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
;
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 *));
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))
739 list
[i
++] = cur
->prop_name
;
743 return (NWAM_SUCCESS
);