2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <auth_list.h>
2N/A#include <assert.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <string.h>
2N/A#include <libintl.h>
2N/A#include <libnwam.h>
2N/A#include "libnwam_impl.h"
2N/A
2N/A/*
2N/A * Generic object manipulation functions. Given an object handle and
2N/A * other parameters, create/destroy objects, walk them, walk their
2N/A * properties, modify/retrieve/delete properties, enable/disable them,
2N/A * etc. All object handles are "struct nwam_handle *" objects, sharing
2N/A * the same description based on the object type, name, original name
2N/A * (used in renaming) and associated data representing properties.
2N/A */
2N/A
2N/Anwam_error_t
2N/Anwam_handle_create(nwam_object_type_t type, const char *name,
2N/A struct nwam_handle **hpp)
2N/A{
2N/A
2N/A assert(name != NULL && hpp != NULL);
2N/A
2N/A if (strnlen(name, NWAM_MAX_NAME_LEN) > NWAM_MAX_NAME_LEN) {
2N/A *hpp = NULL;
2N/A return (NWAM_INVALID_ARG);
2N/A }
2N/A
2N/A if ((*hpp = calloc(1, sizeof (struct nwam_handle))) == NULL)
2N/A return (NWAM_NO_MEMORY);
2N/A
2N/A (*hpp)->nwh_object_type = type;
2N/A (void) strlcpy((*hpp)->nwh_name, name, strlen(name) + 1);
2N/A (*hpp)->nwh_committed = B_FALSE;
2N/A (*hpp)->nwh_data = NULL;
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_lists_to_handle(nvlist_t *idp, nvlist_t *objp, nwam_object_type_t type,
2N/A struct nwam_handle **hpp)
2N/A{
2N/A char *name;
2N/A nwam_error_t err;
2N/A
2N/A /*
2N/A * Interface NCUs will have "_ifname" in the idlist instead of "name".
2N/A * Link NCUs will have "linkname" in the idlist instead of "name". If
2N/A * looking up "name" fails for an NCU, lookup "_ifname" and
2N/A * "linkname".
2N/A */
2N/A if (nvlist_lookup_string(idp, "name", &name) != 0 &&
2N/A (type == NWAM_OBJECT_TYPE_NCU &&
2N/A (nvlist_lookup_string(idp, "linkname", &name) != 0 &&
2N/A nvlist_lookup_string(idp, "_ifname", &name) != 0)))
2N/A return (NWAM_INVALID_ARG);
2N/A
2N/A if ((err = nwam_handle_create(type, name, hpp)) != NWAM_SUCCESS)
2N/A return (err);
2N/A
2N/A (*hpp)->nwh_data = objp;
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Read object of specified type from dbname.
2N/A */
2N/Anwam_error_t
2N/Anwam_read(nwam_object_type_t type, const char *dbname, const char *name,
2N/A uint64_t flags, struct nwam_handle **hpp)
2N/A{
2N/A nwam_error_t err;
2N/A netcfg_error_t nerr;
2N/A nvlist_t *idlist;
2N/A char *keyname, *fobjname;
2N/A
2N/A assert(name != NULL && hpp != NULL);
2N/A
2N/A if ((err = nwam_valid_flags(flags, 0)) != NWAM_SUCCESS)
2N/A return (err);
2N/A if ((err = nwam_handle_create(type, name, hpp)) != NWAM_SUCCESS)
2N/A return (err);
2N/A
2N/A if ((nerr = netcfg_init_idlist(&idlist, dbname)) != NETCFG_SUCCESS)
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A
2N/A /*
2N/A * For interface NCUs, the keyname is "_ifname" instead of "name".
2N/A * For link NCUs, the keyname is "linkname" instead of "name".
2N/A */
2N/A if (type == NWAM_OBJECT_TYPE_NCU) {
2N/A if (strncasecmp(dbname, NWAM_IPADM_CONF_FILE_PRE,
2N/A sizeof (NWAM_IPADM_CONF_FILE_PRE)-1) == 0)
2N/A keyname = "_ifname";
2N/A else
2N/A keyname = "linkname";
2N/A } else {
2N/A keyname = "name";
2N/A }
2N/A
2N/A if ((nerr = netcfg_add_idlist(idlist, keyname, (*hpp)->nwh_name))
2N/A != NETCFG_SUCCESS) {
2N/A nvlist_free(idlist);
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A }
2N/A
2N/A if ((nerr = netcfg_read_object(&idlist, flags, &(*hpp)->nwh_data))
2N/A != NETCFG_SUCCESS) {
2N/A nvlist_free(idlist);
2N/A free(*hpp);
2N/A *hpp = NULL;
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A }
2N/A
2N/A /*
2N/A * The object name might need to be case-corrected; update the name in
2N/A * the handle with the name value from the returned idlist.
2N/A */
2N/A if (nvlist_lookup_string(idlist, keyname, &fobjname) == 0) {
2N/A (void) strlcpy((*hpp)->nwh_name, fobjname,
2N/A sizeof ((*hpp)->nwh_name));
2N/A }
2N/A
2N/Adone:
2N/A (*hpp)->nwh_committed = B_TRUE;
2N/A
2N/A nvlist_free(idlist);
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Create simply creates the handle - the object-specific function must
2N/A * then fill in property values.
2N/A */
2N/Anwam_error_t
2N/Anwam_create(nwam_object_type_t type, const char *dbname, const char *name,
2N/A struct nwam_handle **hpp)
2N/A{
2N/A struct nwam_handle *hp;
2N/A nwam_error_t err;
2N/A
2N/A assert(hpp != NULL && name != NULL);
2N/A
2N/A if (nwam_read(type, dbname, name, 0, &hp) == NWAM_SUCCESS) {
2N/A nwam_free(hp, B_TRUE);
2N/A return (NWAM_ENTITY_EXISTS);
2N/A }
2N/A /* Create handle */
2N/A if ((err = nwam_handle_create(type, name, hpp)) != NWAM_SUCCESS)
2N/A return (err);
2N/A
2N/A /* Create new object list */
2N/A return (nwam_alloc_object_list(&((*hpp)->nwh_data)));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_get_name(struct nwam_handle *hp, char **namep)
2N/A{
2N/A assert(hp != NULL && namep != NULL);
2N/A
2N/A if ((*namep = strdup(hp->nwh_name)) == NULL) {
2N/A *namep = NULL;
2N/A return (NWAM_NO_MEMORY);
2N/A }
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_set_name(struct nwam_handle *hp, const char *name)
2N/A{
2N/A assert(hp != NULL && name != NULL);
2N/A
2N/A if (hp->nwh_committed)
2N/A return (NWAM_ENTITY_READ_ONLY);
2N/A
2N/A if (strlen(name) >= sizeof (hp->nwh_name))
2N/A return (NWAM_INVALID_ARG);
2N/A
2N/A (void) strcpy(hp->nwh_name, name);
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Astatic void
2N/Anwam_select_free(void **arg)
2N/A{
2N/A struct nwam_handle *hp = *arg;
2N/A
2N/A nwam_free(hp, B_FALSE);
2N/A *arg = NULL;
2N/A}
2N/A
2N/A/*
2N/A * Generic walk function takes the standard walk arguments, and in addition
2N/A * takes a selection callback that is object-specific. If this returns
2N/A * 0, the object is a valid selection for the walk and the callback is called.
2N/A * Otherwise, it is skipped.
2N/A */
2N/A/* ARGSUSED */
2N/Anwam_error_t
2N/Anwam_walk(const char *dbname, netcfg_walkcb_t *cb, void *data, uint64_t flags,
2N/A int *retp, netcfg_selectcb_t *selectcb)
2N/A{
2N/A nvlist_t *idlist;
2N/A netcfg_error_t ncerr;
2N/A
2N/A if ((ncerr = netcfg_init_idlist(&idlist, dbname)) != NETCFG_SUCCESS)
2N/A return (netcfg_error_to_nwam_error(ncerr));
2N/A
2N/A ncerr = netcfg_walk_db(&idlist, flags, cb, data, selectcb,
2N/A nwam_select_free, retp);
2N/A
2N/A nvlist_free(idlist);
2N/A return (netcfg_error_to_nwam_error(ncerr));
2N/A}
2N/A
2N/Avoid
2N/Anwam_free(struct nwam_handle *hp, boolean_t free_data)
2N/A{
2N/A if (hp != NULL) {
2N/A if (free_data && hp->nwh_data != NULL)
2N/A nwam_free_object_list(hp->nwh_data);
2N/A free(hp);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Copy object represented by oldhp to an object newname, all in container
2N/A * dbname.
2N/A */
2N/Anwam_error_t
2N/Anwam_copy(const char *dbname, struct nwam_handle *oldhp, const char *newname,
2N/A struct nwam_handle **newhpp)
2N/A{
2N/A nwam_error_t err;
2N/A struct nwam_handle *hp;
2N/A
2N/A assert(oldhp != NULL && newname != NULL && newhpp != NULL);
2N/A
2N/A if (nwam_read(oldhp->nwh_object_type, dbname, newname, 0, &hp)
2N/A == NWAM_SUCCESS) {
2N/A nwam_free(hp, B_TRUE);
2N/A return (NWAM_ENTITY_EXISTS);
2N/A }
2N/A
2N/A if ((err = nwam_handle_create(oldhp->nwh_object_type, newname, newhpp))
2N/A != NWAM_SUCCESS)
2N/A return (err);
2N/A if ((err = nwam_dup_object_list(oldhp->nwh_data,
2N/A &((*newhpp)->nwh_data))) != NWAM_SUCCESS) {
2N/A nwam_free(*newhpp, B_TRUE);
2N/A *newhpp = NULL;
2N/A return (err);
2N/A }
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/A/* ARGSUSED3 */
2N/Anwam_error_t
2N/Anwam_walk_props(struct nwam_handle *hp,
2N/A int (*cb)(const char *, nwam_value_t, void *),
2N/A void *data, uint64_t flags, int *retp)
2N/A{
2N/A char *lastpropname = NULL, *propname;
2N/A nwam_value_t value;
2N/A nwam_error_t err;
2N/A int ret = 0;
2N/A
2N/A assert(hp != NULL && hp->nwh_data != NULL && cb != NULL);
2N/A
2N/A if ((err = nwam_valid_flags(flags, 0)) != NWAM_SUCCESS)
2N/A return (err);
2N/A while ((err = nwam_next_object_prop(hp->nwh_data, lastpropname,
2N/A &propname, &value)) == NWAM_SUCCESS) {
2N/A /* skip any object-id-list values */
2N/A if (strcmp(propname, NETCFG_OBJECT_ID_LIST) == 0) {
2N/A nwam_value_free(value);
2N/A lastpropname = propname;
2N/A continue;
2N/A }
2N/A
2N/A ret = cb(propname, value, data);
2N/A if (ret != 0)
2N/A err = NWAM_WALK_HALTED;
2N/A nwam_value_free(value);
2N/A if (err != NWAM_SUCCESS)
2N/A break;
2N/A
2N/A lastpropname = propname;
2N/A }
2N/A
2N/A if (retp != NULL)
2N/A *retp = ret;
2N/A if (err == NWAM_SUCCESS || err == NWAM_LIST_END)
2N/A return (NWAM_SUCCESS);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Note that prior to calling the generic commit function, object-specific
2N/A * validation should be carried out.
2N/A */
2N/Anwam_error_t
2N/Anwam_commit(const char *dbname, struct nwam_handle *hp, uint64_t flags)
2N/A{
2N/A nwam_error_t err;
2N/A netcfg_error_t nerr;
2N/A uint64_t iflags = flags;
2N/A boolean_t is_ncu;
2N/A struct nwam_handle *testhp;
2N/A nwam_action_t action;
2N/A nvlist_t *idlist;
2N/A char *keyname;
2N/A
2N/A assert(hp != NULL);
2N/A
2N/A if ((err = nwam_valid_flags(flags, NWAM_FLAG_OVERRIDE_READ_ONLY))
2N/A != NWAM_SUCCESS)
2N/A return (err);
2N/A
2N/A is_ncu = (hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU);
2N/A
2N/A /*
2N/A * Does object already exist? If not, action is ADD, otherwise REFRESH.
2N/A */
2N/A switch (nwam_read(hp->nwh_object_type, (char *)dbname, hp->nwh_name, 0,
2N/A &testhp)) {
2N/A case NWAM_ENTITY_NOT_FOUND:
2N/A action = NWAM_ACTION_ADD;
2N/A break;
2N/A case NWAM_SUCCESS:
2N/A nwam_free(testhp, B_TRUE);
2N/A /* FALLTHRU */
2N/A default:
2N/A action = NWAM_ACTION_REFRESH;
2N/A break;
2N/A }
2N/A
2N/A if ((nerr = netcfg_init_idlist(&idlist, dbname)) != NETCFG_SUCCESS)
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A
2N/A /*
2N/A * If this is an NCU, it must be a link NCU, as interface NCUs
2N/A * are written using libipadm function calls. dladm db entries
2N/A * use "linkname" for the object name key, rather than "name".
2N/A */
2N/A keyname = is_ncu ? "linkname" : "name";
2N/A if ((nerr = netcfg_add_idlist(idlist, keyname, hp->nwh_name))
2N/A != NETCFG_SUCCESS) {
2N/A nvlist_free(idlist);
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A }
2N/A
2N/A if ((nerr = netcfg_update_object(&idlist, iflags, &hp->nwh_data))
2N/A != NETCFG_SUCCESS)
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A
2N/A hp->nwh_committed = B_TRUE;
2N/A
2N/A if (is_ncu) {
2N/A char *typedname, *ncpname;
2N/A
2N/A (void) nwam_ncu_name_to_typed_name(hp->nwh_name,
2N/A nwam_dbname_to_ncu_type(dbname), &typedname);
2N/A ncpname = nwam_ncp_name_from_dbname(dbname);
2N/A (void) nwam_request_action(hp->nwh_object_type, typedname,
2N/A ncpname, action);
2N/A free(typedname);
2N/A free(ncpname);
2N/A } else {
2N/A (void) nwam_request_action(hp->nwh_object_type, hp->nwh_name,
2N/A NULL, action);
2N/A }
2N/A
2N/Adone:
2N/A nvlist_free(idlist);
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Anwam_is_active(struct nwam_handle *hp)
2N/A{
2N/A nwam_state_t state;
2N/A nwam_aux_state_t aux;
2N/A
2N/A return ((nwam_get_state(NULL, hp, &state, &aux) == NWAM_SUCCESS &&
2N/A state == NWAM_STATE_ONLINE));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_destroy(const char *dbname, struct nwam_handle *hp, uint64_t flags)
2N/A{
2N/A nwam_error_t err;
2N/A netcfg_error_t nerr;
2N/A char *name, *keyname;
2N/A boolean_t is_ncp, is_ncu;
2N/A nvlist_t *idlist = NULL;
2N/A
2N/A assert(hp != NULL);
2N/A
2N/A if ((err = nwam_valid_flags(flags, NWAM_FLAG_DO_NOT_FREE |
2N/A NWAM_FLAG_OVERRIDE_READ_ONLY)) != NWAM_SUCCESS)
2N/A return (err);
2N/A
2N/A is_ncp = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCP;
2N/A is_ncu = hp->nwh_object_type == NWAM_OBJECT_TYPE_NCU;
2N/A name = hp->nwh_name;
2N/A
2N/A /* Check if object is active */
2N/A if (!is_ncp && !is_ncu && nwam_is_active(hp))
2N/A return (NWAM_ENTITY_IN_USE);
2N/A
2N/A if ((nerr = netcfg_init_idlist(&idlist, dbname)) != NETCFG_SUCCESS)
2N/A goto done;
2N/A
2N/A /*
2N/A * Interface NCUs are not destroyed through nwam_destroy(). They are
2N/A * removed using libipadm function calls. Thus, there's no need for a
2N/A * special case to add "_ifname". Link NCUs have "linkname" for the
2N/A * key instead of "name".
2N/A */
2N/A if (strncasecmp(dbname, NWAM_DATALINK_CONF_FILE_PRE,
2N/A sizeof (NWAM_DATALINK_CONF_FILE_PRE)-1) == 0)
2N/A keyname = "linkname";
2N/A else
2N/A keyname = "name";
2N/A
2N/A if ((nerr = netcfg_add_idlist(idlist, keyname, name))
2N/A != NETCFG_SUCCESS) {
2N/A nvlist_free(idlist);
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A }
2N/A
2N/A /* remove the object */
2N/A nerr = netcfg_remove_object(&idlist, flags);
2N/A
2N/A if (is_ncu) {
2N/A char *typedname, *ncpname;
2N/A
2N/A (void) nwam_ncu_name_to_typed_name(hp->nwh_name,
2N/A nwam_dbname_to_ncu_type(dbname), &typedname);
2N/A ncpname = nwam_ncp_name_from_dbname(dbname);
2N/A (void) nwam_request_action(hp->nwh_object_type, typedname,
2N/A ncpname, NWAM_ACTION_DESTROY);
2N/A free(typedname);
2N/A free(ncpname);
2N/A } else {
2N/A (void) nwam_request_action(hp->nwh_object_type, name, NULL,
2N/A NWAM_ACTION_DESTROY);
2N/A }
2N/A
2N/Adone:
2N/A if ((nerr == NETCFG_SUCCESS) && !(flags & NWAM_FLAG_DO_NOT_FREE))
2N/A nwam_free(hp, B_TRUE);
2N/A
2N/A nvlist_free(idlist);
2N/A
2N/A return (netcfg_error_to_nwam_error(nerr));
2N/A}
2N/A
2N/A/*
2N/A * Enable/disable functions assume prior checking of activation mode
2N/A * to ensure an enable/disable action is valid for the object. "parent" in these
2N/A * functions specifies the NCP for NCUs.
2N/A */
2N/Anwam_error_t
2N/Anwam_enable(const char *parent, struct nwam_handle *hp)
2N/A{
2N/A return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
2N/A parent, NWAM_ACTION_ENABLE));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_disable(const char *parent, struct nwam_handle *hp)
2N/A{
2N/A return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
2N/A parent, NWAM_ACTION_DISABLE));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_offline(const char *parent, struct nwam_handle *hp)
2N/A{
2N/A return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
2N/A parent, NWAM_ACTION_OFFLINE));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_online(const char *parent, struct nwam_handle *hp)
2N/A{
2N/A return (nwam_request_action(hp->nwh_object_type, hp->nwh_name,
2N/A parent, NWAM_ACTION_ONLINE));
2N/A}
2N/A
2N/A
2N/Anwam_error_t
2N/Anwam_get_state(const char *parent, struct nwam_handle *hp, nwam_state_t *statep,
2N/A nwam_aux_state_t *auxp)
2N/A{
2N/A assert(hp != NULL && statep != NULL && auxp != NULL);
2N/A
2N/A return (nwam_request_state(hp->nwh_object_type, hp->nwh_name, parent,
2N/A statep, auxp));
2N/A}
2N/A
2N/Astruct nwam_prop_table_entry *
2N/Anwam_get_prop_table_entry(struct nwam_prop_table table, const char *propname)
2N/A{
2N/A struct nwam_prop_table_entry *cur = table.entries;
2N/A struct nwam_prop_table_entry *end = cur + table.num_entries;
2N/A
2N/A assert(propname != NULL);
2N/A
2N/A for (; cur < end; cur++) {
2N/A if (strcmp(propname, cur->prop_name) == 0)
2N/A return (cur);
2N/A }
2N/A return (NULL);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_get_prop_description(struct nwam_prop_table table, const char *propname,
2N/A const char **descriptionp)
2N/A{
2N/A struct nwam_prop_table_entry *pte;
2N/A
2N/A assert(propname != NULL && descriptionp != NULL);
2N/A
2N/A if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL) {
2N/A *descriptionp = NULL;
2N/A return (NWAM_INVALID_ARG);
2N/A }
2N/A
2N/A *descriptionp = dgettext(TEXT_DOMAIN, pte->prop_description);
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_get_prop_type(struct nwam_prop_table table, const char *propname,
2N/A nwam_value_type_t *typep)
2N/A{
2N/A struct nwam_prop_table_entry *pte;
2N/A
2N/A assert(propname != NULL && typep != NULL);
2N/A
2N/A if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
2N/A return (NWAM_INVALID_ARG);
2N/A
2N/A *typep = pte->prop_type;
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_prop_multivalued(struct nwam_prop_table table, const char *propname,
2N/A boolean_t *multip)
2N/A{
2N/A struct nwam_prop_table_entry *pte;
2N/A
2N/A assert(propname != NULL && multip != NULL);
2N/A
2N/A if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
2N/A return (NWAM_INVALID_ARG);
2N/A
2N/A if (pte->prop_max_numvalues > 1)
2N/A *multip = B_TRUE;
2N/A else
2N/A *multip = B_FALSE;
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_prop_read_only(struct nwam_prop_table table, const char *propname,
2N/A boolean_t *readp)
2N/A{
2N/A struct nwam_prop_table_entry *pte;
2N/A
2N/A assert(propname != NULL && readp != NULL);
2N/A
2N/A if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL)
2N/A return (NWAM_INVALID_ARG);
2N/A
2N/A *readp = pte->prop_is_readonly;
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Structure used to pass in prop table and errprop string pointer to internal
2N/A * validate function.
2N/A */
2N/Astruct validate_internal_arg {
2N/A struct nwam_prop_table table;
2N/A const char **errpropp;
2N/A};
2N/A
2N/A/*
2N/A * Callback used by nwam_walk_props() in nwam_validate(), and
2N/A * by nwam_validate_prop() to determine that the number, type and
2N/A * range of values are correct, and that validation function (if present)
2N/A * succeeds.
2N/A */
2N/Astatic int
2N/Anwam_validate_prop_internal(const char *propname, nwam_value_t value,
2N/A void *arg)
2N/A{
2N/A struct validate_internal_arg *via = arg;
2N/A struct nwam_prop_table table = via->table;
2N/A const char **errpropp = via->errpropp;
2N/A struct nwam_prop_table_entry *pte;
2N/A nwam_error_t err;
2N/A nwam_value_type_t type;
2N/A uint_t numvalues;
2N/A int i;
2N/A
2N/A if ((err = nwam_value_get_numvalues(value, &numvalues))
2N/A != NWAM_SUCCESS ||
2N/A (err = nwam_value_get_type(value, &type)) != NWAM_SUCCESS) {
2N/A if (errpropp != NULL)
2N/A *errpropp = propname;
2N/A return (err);
2N/A }
2N/A if ((pte = nwam_get_prop_table_entry(table, propname)) == NULL) {
2N/A /*
2N/A * Property not found in the property table. There's no way
2N/A * to validate this property; hence, return SUCCESS to
2N/A * continue walk and validation of other properties.
2N/A */
2N/A return (NWAM_SUCCESS);
2N/A }
2N/A
2N/A /* have we get expected number of values? */
2N/A if (numvalues < pte->prop_min_numvalues ||
2N/A numvalues > pte->prop_max_numvalues) {
2N/A if (errpropp != NULL)
2N/A *errpropp = propname;
2N/A if (numvalues < 1)
2N/A return (NWAM_ENTITY_NO_VALUE);
2N/A else
2N/A return (NWAM_ENTITY_INVALID_VALUE);
2N/A }
2N/A /* Ensure type matches */
2N/A if (numvalues > 0) {
2N/A for (i = 0; i < numvalues; i++) {
2N/A if (pte->prop_type != type) {
2N/A if (errpropp != NULL)
2N/A *errpropp = propname;
2N/A return (NWAM_ENTITY_TYPE_MISMATCH);
2N/A
2N/A }
2N/A }
2N/A }
2N/A /* Call property-specific validation function */
2N/A if (pte->prop_validate != NULL) {
2N/A err = pte->prop_validate(value);
2N/A if (err != NWAM_SUCCESS && errpropp != NULL)
2N/A *errpropp = propname;
2N/A return (err);
2N/A }
2N/A
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_validate_prop(struct nwam_prop_table table, struct nwam_handle *hp,
2N/A const char *propname, nwam_value_t value)
2N/A{
2N/A struct validate_internal_arg via;
2N/A
2N/A assert(hp != NULL && propname != NULL);
2N/A
2N/A via.table = table;
2N/A via.errpropp = NULL;
2N/A
2N/A return ((nwam_error_t)nwam_validate_prop_internal(propname,
2N/A value, &via));
2N/A}
2N/A
2N/Anwam_error_t
2N/Anwam_validate(struct nwam_prop_table table, struct nwam_handle *hp,
2N/A const char **errpropp)
2N/A{
2N/A struct validate_internal_arg via;
2N/A nwam_error_t err1, err2;
2N/A
2N/A assert(hp != NULL);
2N/A
2N/A via.table = table;
2N/A via.errpropp = errpropp;
2N/A
2N/A err1 = nwam_walk_props(hp, nwam_validate_prop_internal, &via,
2N/A 0, (int *)&err2);
2N/A if (err1 != NWAM_SUCCESS)
2N/A return (err2);
2N/A return (NWAM_SUCCESS);
2N/A}
2N/A
2N/A/*
2N/A * Given the type and class flag representations, return the list of properties
2N/A * that can be set for that type/class combination. Note this list is a complete
2N/A * property list that includes both the required and the optional properties.
2N/A * The type and class flags are only used for NCU objects at present.
2N/A *
2N/A * Caller needs to free prop_list.
2N/A */
2N/Anwam_error_t
2N/Anwam_get_default_proplist(struct nwam_prop_table table,
2N/A uint64_t type, uint64_t class, const char ***prop_list, uint_t *numvalues)
2N/A{
2N/A struct nwam_prop_table_entry *cur = table.entries;
2N/A struct nwam_prop_table_entry *end = cur + table.num_entries;
2N/A int i = 0;
2N/A const char **list = NULL;
2N/A
2N/A assert(prop_list != NULL && numvalues != NULL);
2N/A
2N/A /* Construct a list of all properties for required type/class */
2N/A list = calloc(table.num_entries, sizeof (char *));
2N/A if (list == NULL) {
2N/A *prop_list = NULL;
2N/A *numvalues = 0;
2N/A return (NWAM_NO_MEMORY);
2N/A }
2N/A for (; cur < end; cur++) {
2N/A if (((type & cur->prop_type_membership) == 0) ||
2N/A ((class & cur->prop_class_membership) == 0))
2N/A continue;
2N/A list[i++] = cur->prop_name;
2N/A }
2N/A *numvalues = i;
2N/A *prop_list = list;
2N/A return (NWAM_SUCCESS);
2N/A}