#include <assert.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include "libnwam_impl.h"
#include <libintl.h>
#include <libnwam.h>
nwam_error_t
nwam_handle_create(nwam_object_type_t type, const char *name,
struct nwam_handle **hpp)
{
assert(name != NULL && hpp != NULL);
if (strnlen(name, NWAM_MAX_NAME_LEN) > NWAM_MAX_NAME_LEN) {
*hpp = NULL;
return (NWAM_INVALID_ARG);
}
if ((*hpp = calloc(1, sizeof (struct nwam_handle))) == NULL)
return (NWAM_NO_MEMORY);
(*hpp)->nwh_object_type = type;
(void) strlcpy((*hpp)->nwh_name, name, strlen(name) + 1);
(*hpp)->nwh_committed = B_FALSE;
(*hpp)->nwh_data = NULL;
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_read(nwam_object_type_t type, const char *dbname, const char *name,
uint64_t flags, struct nwam_handle **hpp)
{
nwam_error_t err;
char dbname_copy[MAXPATHLEN];
assert(name != NULL && hpp != NULL);
if (dbname != NULL)
(void) strlcpy(dbname_copy, dbname, sizeof (dbname_copy));
if ((err = nwam_valid_flags(flags, NWAM_FLAG_BLOCKING)) != NWAM_SUCCESS)
return (err);
if ((err = nwam_handle_create(type, name, hpp)) != NWAM_SUCCESS)
return (err);
if ((err = nwam_read_object_from_backend
(dbname != NULL ? dbname_copy : NULL,
type == NWAM_OBJECT_TYPE_NCP ? NULL : (*hpp)->nwh_name, flags,
&(*hpp)->nwh_data)) != NWAM_SUCCESS) {
free(*hpp);
*hpp = NULL;
return (err);
}
if (type == NWAM_OBJECT_TYPE_NCP && dbname != NULL) {
char *ncpname;
if (nwam_ncp_file_to_name(dbname_copy, &ncpname)
== NWAM_SUCCESS) {
(void) strlcpy((*hpp)->nwh_name, ncpname,
sizeof ((*hpp)->nwh_name));
free(ncpname);
}
}
(*hpp)->nwh_committed = B_TRUE;
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_create(nwam_object_type_t type, const char *dbname, const char *name,
struct nwam_handle **hpp)
{
struct nwam_handle *hp;
assert(hpp != NULL && name != NULL);
if (nwam_read(type, dbname, name, 0, &hp) == NWAM_SUCCESS) {
nwam_free(hp);
return (NWAM_ENTITY_EXISTS);
}
return (nwam_handle_create(type, name, hpp));
}
nwam_error_t
nwam_get_name(struct nwam_handle *hp, char **namep)
{
assert(hp != NULL && namep != NULL);
if ((*namep = strdup(hp->nwh_name)) == NULL) {
*namep = NULL;
return (NWAM_NO_MEMORY);
}
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_set_name(struct nwam_handle *hp, const char *name)
{
assert(hp != NULL && name != NULL);
if (hp->nwh_committed)
return (NWAM_ENTITY_READ_ONLY);
if (strlen(name) >= sizeof (hp->nwh_name))
return (NWAM_INVALID_ARG);
(void) strcpy(hp->nwh_name, name);
return (NWAM_SUCCESS);
}
static int
name_cmp(const void *c1, const void *c2)
{
nwam_ncu_type_t t1, t2;
char *n1, *n2;
if (nwam_ncu_typed_name_to_name(*(const char **)c1, &t1, &n1)
== NWAM_SUCCESS &&
nwam_ncu_typed_name_to_name(*(const char **)c2, &t2, &n2)
== NWAM_SUCCESS) {
int ret = strcasecmp(n1, n2);
free(n1);
free(n2);
if (ret == 0) {
if (t1 < t2)
ret = -1;
else if (t1 > t2)
ret = 1;
}
return (ret);
}
return (strcasecmp(*(const char **)c1, *(const char **)c2));
}
nwam_error_t
nwam_walk(nwam_object_type_t type, const char *dbname,
int(*cb)(struct nwam_handle *, void *),
void *data, uint64_t flags, int *retp,
int(*selectcb)(struct nwam_handle *, uint64_t, void *))
{
void *objlist;
nwam_value_t value;
char **object_names;
uint_t i, num_objects = 0;
struct nwam_handle *hp;
nwam_error_t err;
int ret = 0;
assert(cb != NULL);
if ((err = nwam_read_object_from_backend((char *)dbname, NULL, flags,
&objlist)) != NWAM_SUCCESS) {
if (err == NWAM_ENTITY_NOT_FOUND) {
return (NWAM_SUCCESS);
}
return (err);
}
if ((err = nwam_get_prop_value(objlist, NWAM_OBJECT_NAMES_STRING,
&value)) != NWAM_SUCCESS) {
nwam_free_object_list(objlist);
return (err);
}
err = nwam_value_get_string_array(value, &object_names, &num_objects);
nwam_free_object_list(objlist);
if (err != NWAM_SUCCESS) {
nwam_value_free(value);
return (err);
}
qsort(object_names, num_objects, sizeof (char *), name_cmp);
for (i = 0; i < num_objects; i++) {
err = nwam_read(type, dbname, object_names[i],
flags & NWAM_FLAG_GLOBAL_MASK, &hp);
if (err == NWAM_ENTITY_NOT_FOUND)
continue;
if (err != NWAM_SUCCESS) {
nwam_value_free(value);
return (err);
}
if ((selectcb == NULL) || (selectcb(hp, flags, data) == 0)) {
ret = cb(hp, data);
if (ret != 0) {
nwam_free(hp);
nwam_value_free(value);
if (retp != NULL)
*retp = ret;
return (NWAM_WALK_HALTED);
}
}
nwam_free(hp);
}
nwam_value_free(value);
if (retp != NULL)
*retp = ret;
return (err);
}
void
nwam_free(struct nwam_handle *hp)
{
if (hp != NULL) {
if (hp->nwh_data != NULL)
nwam_free_object_list(hp->nwh_data);
free(hp);
}
}
nwam_error_t
nwam_copy(const char *dbname, struct nwam_handle *oldhp, const char *newname,
struct nwam_handle **newhpp)
{
nwam_error_t err;
struct nwam_handle *hp;
assert(oldhp != NULL && newname != NULL && newhpp != NULL);
if (nwam_read(oldhp->nwh_object_type, dbname, newname, 0, &hp)
== NWAM_SUCCESS) {
nwam_free(hp);
return (NWAM_ENTITY_EXISTS);
}
if ((err = nwam_handle_create(oldhp->nwh_object_type, newname, newhpp))
!= NWAM_SUCCESS)
return (err);
if ((err = nwam_dup_object_list(oldhp->nwh_data,
&((*newhpp)->nwh_data))) != NWAM_SUCCESS) {
nwam_free(*newhpp);
*newhpp = NULL;
return (err);
}
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_walk_props(struct nwam_handle *hp,
int (*cb)(const char *, nwam_value_t, void *),
void *data, uint64_t flags, int *retp)
{
char *lastpropname = NULL, *propname;
nwam_value_t value;
nwam_error_t err;
int ret = 0;
assert(hp != NULL && hp->nwh_data != NULL && cb != NULL);
if ((err = nwam_valid_flags(flags, 0)) != NWAM_SUCCESS)
return (err);
while ((err = nwam_next_object_prop(hp->nwh_data, lastpropname,
&propname, &value)) == NWAM_SUCCESS) {
ret = cb(propname, value, data);
if (ret != 0)
err = NWAM_WALK_HALTED;
nwam_value_free(value);
if (err != NWAM_SUCCESS)
break;
lastpropname = propname;
}
if (retp != NULL)
*retp = ret;
if (err == NWAM_SUCCESS || err == NWAM_LIST_END)
return (NWAM_SUCCESS);
return (err);
}
nwam_error_t
nwam_commit(const char *dbname, struct nwam_handle *hp, uint64_t flags)
{
nwam_error_t err;
uint64_t iflags = flags;
boolean_t is_ncu;
struct nwam_handle *testhp;
nwam_action_t action;
assert(hp != NULL);
if ((err = nwam_valid_flags(flags,
NWAM_FLAG_BLOCKING | NWAM_FLAG_CREATE |
(hp->nwh_object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN ?
NWAM_FLAG_ENTITY_KNOWN_WLAN : NWAM_FLAG_ENTITY_ENABLE)))
!= NWAM_SUCCESS)
return (err);
is_ncu = (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU);
switch (nwam_read(hp->nwh_object_type, (char *)dbname, hp->nwh_name, 0,
&testhp)) {
case NWAM_ENTITY_NOT_FOUND:
action = NWAM_ACTION_ADD;
break;
case NWAM_SUCCESS:
nwam_free(testhp);
if (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP)
return (NWAM_ENTITY_EXISTS);
default:
action = NWAM_ACTION_REFRESH;
break;
}
err = nwam_update_object_in_backend((char *)dbname,
hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP ? NULL : hp->nwh_name,
iflags, hp->nwh_data);
if (err != NWAM_SUCCESS)
return (err);
hp->nwh_committed = B_TRUE;
if (is_ncu) {
char *ncpname;
if (nwam_ncp_file_to_name(dbname, &ncpname) == NWAM_SUCCESS) {
(void) nwam_request_action(hp->nwh_object_type,
hp->nwh_name, ncpname, action);
free(ncpname);
}
} else {
(void) nwam_request_action(hp->nwh_object_type, hp->nwh_name,
NULL, action);
}
return (NWAM_SUCCESS);
}
static boolean_t
nwam_is_active(struct nwam_handle *hp)
{
nwam_state_t state;
nwam_aux_state_t aux;
return ((nwam_get_state(NULL, hp, &state, &aux) == NWAM_SUCCESS &&
state == NWAM_STATE_ONLINE));
}
nwam_error_t
nwam_destroy(const char *dbname, struct nwam_handle *hp, uint64_t flags)
{
nwam_error_t err;
char *name;
boolean_t is_ncp, is_ncu;
assert(hp != NULL);
if ((err = nwam_valid_flags(flags,
NWAM_FLAG_BLOCKING | NWAM_FLAG_DO_NOT_FREE |
(hp->nwh_object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN ?
NWAM_FLAG_ENTITY_KNOWN_WLAN : 0))) != NWAM_SUCCESS)
return (err);
is_ncp = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP;
is_ncu = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU;
name = hp->nwh_name;
if (!is_ncp && !is_ncu && nwam_is_active(hp))
return (NWAM_ENTITY_IN_USE);
err = nwam_remove_object_from_backend((char *)dbname,
is_ncp ? NULL : name, flags);
if (is_ncu) {
char *ncpname;
if (nwam_ncp_file_to_name(dbname, &ncpname) == NWAM_SUCCESS) {
(void) nwam_request_action(hp->nwh_object_type, name,
ncpname, NWAM_ACTION_DESTROY);
free(ncpname);
}
} else {
(void) nwam_request_action(hp->nwh_object_type, name, NULL,
NWAM_ACTION_DESTROY);
}
if ((err == NWAM_SUCCESS) && !(flags & NWAM_FLAG_DO_NOT_FREE))
nwam_free(hp);
return (err);
}
nwam_error_t
nwam_enable(const char *parent, struct nwam_handle *hp)
{
return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
parent, NWAM_ACTION_ENABLE));
}
nwam_error_t
nwam_disable(const char *parent, struct nwam_handle *hp)
{
return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
parent, NWAM_ACTION_DISABLE));
}
nwam_error_t
nwam_get_state(const char *parent, struct nwam_handle *hp, nwam_state_t *statep,
nwam_aux_state_t *auxp)
{
return (nwam_request_state(hp->nwh_object_type, hp->nwh_name, parent,
statep, auxp));
}
struct nwam_prop_table_entry *
nwam_get_prop_table_entry(struct nwam_prop_table table, const char *propname)
{
struct nwam_prop_table_entry *cur = table.entries;
struct nwam_prop_table_entry *end = cur + table.num_entries;
assert(propname != NULL);
for (; cur < end; cur++) {
if (strcmp(propname, cur->prop_name) == 0)
return (cur);
}
return (NULL);
}
nwam_error_t
nwam_get_prop_description(struct nwam_prop_table table, const char *propname,
const char **descriptionp)
{
struct nwam_prop_table_entry *pte;
assert(propname != NULL && descriptionp != NULL);
if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL) {
*descriptionp = NULL;
return (NWAM_INVALID_ARG);
}
*descriptionp = dgettext(TEXT_DOMAIN, pte->prop_description);
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_get_prop_type(struct nwam_prop_table table, const char *propname,
nwam_value_type_t *typep)
{
struct nwam_prop_table_entry *pte;
assert(propname != NULL && typep != NULL);
if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
return (NWAM_INVALID_ARG);
*typep = pte->prop_type;
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_prop_multivalued(struct nwam_prop_table table, const char *propname,
boolean_t *multip)
{
struct nwam_prop_table_entry *pte;
assert(propname != NULL && multip != NULL);
if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
return (NWAM_INVALID_ARG);
if (pte->prop_max_numvalues > 1)
*multip = B_TRUE;
else
*multip = B_FALSE;
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_prop_read_only(struct nwam_prop_table table, const char *propname,
boolean_t *readp)
{
struct nwam_prop_table_entry *pte;
assert(propname != NULL && readp != NULL);
if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
return (NWAM_INVALID_ARG);
*readp = (pte->prop_is_readonly && !nwam_uid_is_special());
return (NWAM_SUCCESS);
}
struct validate_internal_arg {
struct nwam_prop_table table;
const char **errpropp;
};
static int
nwam_validate_prop_internal(const char *propname, nwam_value_t value,
void *arg)
{
struct validate_internal_arg *via = arg;
struct nwam_prop_table table = via->table;
const char **errpropp = via->errpropp;
struct nwam_prop_table_entry *pte;
nwam_error_t err;
nwam_value_type_t type;
uint_t numvalues;
int i;
if ((err = nwam_value_get_numvalues(value, &numvalues))
!= NWAM_SUCCESS ||
(err = nwam_value_get_type(value, &type)) != NWAM_SUCCESS) {
if (errpropp != NULL)
*errpropp = propname;
return (err);
}
if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
return (NWAM_INVALID_ARG);
if (numvalues < pte->prop_min_numvalues ||
numvalues > pte->prop_max_numvalues) {
if (errpropp != NULL)
*errpropp = propname;
if (numvalues < 1)
return (NWAM_ENTITY_NO_VALUE);
else
return (NWAM_ENTITY_INVALID_VALUE);
}
if (numvalues > 0) {
for (i = 0; i < numvalues; i++) {
if (pte->prop_type != type) {
if (errpropp != NULL)
*errpropp = propname;
return (NWAM_ENTITY_TYPE_MISMATCH);
}
}
}
if (pte->prop_validate != NULL) {
err = pte->prop_validate(value);
if (err != NWAM_SUCCESS && errpropp != NULL)
*errpropp = propname;
return (err);
}
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_validate_prop(struct nwam_prop_table table, struct nwam_handle *hp,
const char *propname, nwam_value_t value)
{
struct validate_internal_arg via;
assert(hp != NULL && propname != NULL);
via.table = table;
via.errpropp = NULL;
return ((nwam_error_t)nwam_validate_prop_internal(propname,
value, &via));
}
nwam_error_t
nwam_validate(struct nwam_prop_table table, struct nwam_handle *hp,
const char **errpropp)
{
struct validate_internal_arg via;
nwam_error_t err1, err2;
assert(hp != NULL);
via.table = table;
via.errpropp = errpropp;
err1 = nwam_walk_props(hp, nwam_validate_prop_internal, &via,
0, (int *)&err2);
if (err1 != NWAM_SUCCESS)
return (err2);
return (NWAM_SUCCESS);
}
nwam_error_t
nwam_get_default_proplist(struct nwam_prop_table table,
uint64_t type, uint64_t class, const char ***prop_list, uint_t *numvalues)
{
struct nwam_prop_table_entry *cur = table.entries;
struct nwam_prop_table_entry *end = cur + table.num_entries;
int i = 0;
const char **list = NULL;
assert(prop_list != NULL && numvalues != NULL);
list = calloc(table.num_entries, sizeof (char *));
if (list == NULL) {
*prop_list = NULL;
*numvalues = 0;
return (NWAM_NO_MEMORY);
}
for (; cur < end; cur++) {
if (((type & cur->prop_type_membership) == 0) ||
((class & cur->prop_class_membership) == 0))
continue;
list[i++] = cur->prop_name;
}
*numvalues = i;
*prop_list = list;
return (NWAM_SUCCESS);
}