validation NEW rpc/action/notification validation
diff --git a/src/validation.c b/src/validation.c
index 84975a3..33e6eab 100644
--- a/src/validation.c
+++ b/src/validation.c
@@ -858,8 +858,7 @@
}
LY_ERR
-lyd_validate_siblings_r(struct lyd_node *first, const struct lysc_node *sparent, const struct lys_module *mod,
- int val_opts)
+lyd_validate_final_r(struct lyd_node *first, const struct lysc_node *sparent, const struct lys_module *mod, int val_opts)
{
struct lyd_node *next, *node;
const struct lysc_node *snode;
@@ -904,7 +903,7 @@
LY_LIST_FOR(first, node) {
/* validate all children recursively */
- LY_CHECK_RET(lyd_validate_siblings_r((struct lyd_node *)lyd_node_children(node), node->schema, NULL, val_opts));
+ LY_CHECK_RET(lyd_validate_final_r((struct lyd_node *)lyd_node_children(node), node->schema, NULL, val_opts));
/* set default for containers */
if ((node->schema->nodetype == LYS_CONTAINER) && !(node->schema->flags & LYS_PRESENCE)) {
@@ -1018,13 +1017,51 @@
}
static LY_ERR
+lyd_validate_subtree(struct lyd_node *root, struct ly_set *type_check, struct ly_set *type_meta_check,
+ struct ly_set *when_check, int val_opts)
+{
+ const struct lyd_meta *meta;
+ struct lyd_node *next, *node;
+
+ LYD_TREE_DFS_BEGIN(root, next, node) {
+ /* skip added default nodes */
+ if ((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) {
+ LY_LIST_FOR(node->meta, meta) {
+ /* metadata type resolution */
+ ly_set_add(type_meta_check, (void *)meta, LY_SET_OPT_USEASLIST);
+ }
+
+ if (node->schema->nodetype & LYD_NODE_TERM) {
+ /* node type resolution */
+ ly_set_add(type_check, (void *)node, LY_SET_OPT_USEASLIST);
+ } else if (node->schema->nodetype & LYD_NODE_INNER) {
+ /* new node validation, autodelete */
+ LY_CHECK_RET(lyd_validate_new(lyd_node_children_p((struct lyd_node *)node), node->schema, NULL));
+
+ /* add nested defaults */
+ LY_CHECK_RET(lyd_validate_defaults_r(node, lyd_node_children_p((struct lyd_node *)node), NULL, NULL, type_check,
+ when_check, val_opts));
+ }
+
+ if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
+ /* when evaluation */
+ ly_set_add(when_check, (void *)node, LY_SET_OPT_USEASLIST);
+ }
+ }
+
+ LYD_TREE_DFS_END(root, next, node);
+ }
+
+ return LY_SUCCESS;
+}
+
+static LY_ERR
_lyd_validate(struct lyd_node **tree, const struct lys_module **modules, int mod_count, const struct ly_ctx *ctx,
int val_opts)
{
LY_ERR ret = LY_SUCCESS;
- struct lyd_node *first, *next, *node, **first2;
+ struct lyd_node *first, *next, **first2;
const struct lys_module *mod;
- const struct lyd_meta *meta;
struct ly_set type_check = {0}, type_meta_check = {0}, when_check = {0};
uint32_t i = 0;
@@ -1053,45 +1090,14 @@
}
/* validate new top-level nodes of this module, autodelete */
- ret = lyd_validate_new(first2, NULL, mod);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_new(first2, NULL, mod), cleanup);
/* add all top-level defaults for this module */
- ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &type_check, &when_check, val_opts);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_defaults_r(NULL, first2, NULL, mod, &type_check, &when_check, val_opts), cleanup);
/* process nested nodes */
LY_LIST_FOR(*first2, first) {
- LYD_TREE_DFS_BEGIN(first, next, node) {
- /* skip added default nodes */
- if ((node->flags & (LYD_DEFAULT | LYD_NEW)) != (LYD_DEFAULT | LYD_NEW)) {
- LY_LIST_FOR(node->meta, meta) {
- /* metadata type resolution */
- ly_set_add(&type_meta_check, (void *)meta, LY_SET_OPT_USEASLIST);
- }
-
- if (node->schema->nodetype & LYD_NODE_TERM) {
- /* node type resolution */
- ly_set_add(&type_check, (void *)node, LY_SET_OPT_USEASLIST);
- } else if (node->schema->nodetype & LYD_NODE_INNER) {
- /* new node validation, autodelete */
- ret = lyd_validate_new(lyd_node_children_p((struct lyd_node *)node), node->schema, NULL);
- LY_CHECK_GOTO(ret, cleanup);
-
- /* add nested defaults */
- ret = lyd_validate_defaults_r(node, lyd_node_children_p((struct lyd_node *)node), NULL, NULL, &type_check,
- &when_check, val_opts);
- LY_CHECK_GOTO(ret, cleanup);
- }
-
- if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) && node->schema->when) {
- /* when evaluation */
- ly_set_add(&when_check, (void *)node, LY_SET_OPT_USEASLIST);
- }
- }
-
- LYD_TREE_DFS_END(first, next, node);
- }
+ LY_CHECK_GOTO(ret = lyd_validate_subtree(first, &type_check, &type_meta_check, &when_check, val_opts), cleanup);
}
/* finish incompletely validated terminal values/attributes and when conditions */
@@ -1099,8 +1105,7 @@
LY_CHECK_GOTO(ret, cleanup);
/* perform final validation that assumes the data tree is final */
- ret = lyd_validate_siblings_r(*first2, NULL, mod, val_opts);
- LY_CHECK_GOTO(ret, cleanup);
+ LY_CHECK_GOTO(ret = lyd_validate_final_r(*first2, NULL, mod, val_opts), cleanup);
}
cleanup:
@@ -1121,3 +1126,97 @@
{
return _lyd_validate(tree, modules, mod_count, NULL, val_opts);
}
+
+API LY_ERR
+lyd_validate_rpc_notif(struct lyd_node *op_tree, const struct lyd_node *tree)
+{
+ LY_ERR ret;
+ const struct lyd_node *tree_iter;
+ struct lyd_node *op_iter, *match, *op, *orig_op_parent;
+ uint32_t i, cur_depth, op_depth;
+ struct ly_set type_check = {0}, type_meta_check = {0}, when_check = {0};
+
+ LY_CHECK_ARG_RET(NULL, op_tree, !op_tree->parent, !tree || !tree->parent, LY_EINVAL);
+
+ /* find the operation/notification */
+ LYD_TREE_DFS_BEGIN(op_tree, op_iter, op) {
+ if (op->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
+ break;
+ }
+
+ LYD_TREE_DFS_END(op_tree, op_iter, op);
+ }
+ if (!(op->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
+ LOGERR(LYD_NODE_CTX(op_tree), LY_EINVAL, "No RPC/action/notification to validate found.");
+ return LY_EINVAL;
+ }
+
+ /* learn its depth (top-level being depth 0) */
+ op_depth = 0;
+ for (op_iter = op; op_iter != op_tree; op_iter = (struct lyd_node *)op_iter->parent) {
+ ++op_depth;
+ }
+
+ /* find where to merge op */
+ tree_iter = tree;
+ cur_depth = op_depth;
+ op_iter = op;
+ while (cur_depth) {
+ /* find next op parent */
+ op_iter = op;
+ for (i = 0; i < cur_depth; ++i) {
+ op_iter = (struct lyd_node *)op_iter->parent;
+ }
+
+ /* find op iter in tree */
+ lyd_find_sibling_first(tree_iter, op_iter, &match);
+ if (!match) {
+ break;
+ }
+
+ /* move tree_iter */
+ tree_iter = lyd_node_children(match);
+
+ /* move depth */
+ --cur_depth;
+ }
+
+ /* merge op_iter as tree_iter sibling */
+ orig_op_parent = (struct lyd_node *)op_iter->parent;
+ lyd_unlink_tree(op_iter);
+ lyd_insert_node(NULL, (struct lyd_node **)&tree_iter, op_iter);
+ if (!tree) {
+ tree = tree_iter;
+ }
+
+ /* prevalidate whole operation subtree */
+ LY_CHECK_GOTO(ret = lyd_validate_subtree(op, &type_check, &type_meta_check, &when_check, 0), cleanup);
+
+ /* finish incompletely validated terminal values/attributes and when conditions on the full tree */
+ LY_CHECK_GOTO(ret = lyd_validate_unres((struct lyd_node **)&tree, &when_check, &type_check, &type_meta_check,
+ LYD_JSON, lydjson_resolve_prefix, NULL), cleanup);
+
+ /* perform final validation of the operation/notification */
+ lyd_validate_obsolete(op);
+ if (lysc_node_is_disabled(op->schema, 1)) {
+ LOGVAL(LYD_NODE_CTX(op_tree), LY_VLOG_LYD, op, LY_VCODE_NOIFF, op->schema->name);
+ ret = LY_EVALID;
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(ret = lyd_validate_must(op), cleanup);
+
+ /* final validation of all the descendants */
+ LY_CHECK_GOTO(ret = lyd_validate_final_r((struct lyd_node *)lyd_node_children(op), op->schema, NULL, 0), cleanup);
+
+cleanup:
+ /* restore operation tree */
+ lyd_unlink_tree(op_iter);
+ if (orig_op_parent) {
+ lyd_insert_node(orig_op_parent, NULL, op_iter);
+ }
+
+ ly_set_erase(&type_check, NULL);
+ ly_set_erase(&type_meta_check, NULL);
+ ly_set_erase(&when_check, NULL);
+ return ret;
+}