blob: a950c542b44b6db5abe4a9f9fad99292cce0346f [file] [log] [blame]
Michal Vaskocde73ac2019-11-14 16:10:27 +01001/**
2 * @file validation.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief Validation
5 *
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01006 * Copyright (c) 2019 - 2023 CESNET, z.s.p.o.
Michal Vaskocde73ac2019-11-14 16:10:27 +01007 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
Christian Hopps32874e12021-05-01 09:43:54 -040014#define _GNU_SOURCE /* asprintf, strdup */
Michal Vasko81bc5512020-11-13 18:05:18 +010015
Michal Vaskofbed4ea2020-07-08 10:43:30 +020016#include "validation.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010017
18#include <assert.h>
Radek Krejci77114102021-03-10 15:21:57 +010019#include <limits.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include <stdint.h>
Michal Vasko52927e22020-03-16 17:26:14 +010021#include <stdio.h>
22#include <stdlib.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include <string.h>
Michal Vaskocde73ac2019-11-14 16:10:27 +010024
Michal Vasko69730152020-10-09 16:30:07 +020025#include "compat.h"
Michal Vasko8104fd42020-07-13 11:09:51 +020026#include "diff.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020027#include "hash_table.h"
28#include "log.h"
Michal Vasko8f702ee2024-02-20 15:44:24 +010029#include "ly_common.h"
Radek Krejci7931b192020-06-25 17:05:03 +020030#include "parser_data.h"
Radek Krejci77114102021-03-10 15:21:57 +010031#include "parser_internal.h"
Radek Krejci1b2eef82021-02-17 11:17:27 +010032#include "plugins_exts.h"
Radek Krejcif1ca0ac2021-04-12 16:00:06 +020033#include "plugins_exts/metadata.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020034#include "plugins_types.h"
35#include "set.h"
36#include "tree.h"
Radek Krejci47fab892020-11-05 17:02:41 +010037#include "tree_data.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010038#include "tree_data_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020039#include "tree_schema.h"
Michal Vasko14654712020-02-06 08:35:21 +010040#include "tree_schema_internal.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020041#include "xpath.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010042
Michal Vaskod027f382023-02-10 09:13:25 +010043/**
44 * @brief Check validation error taking into account multi-error validation.
45 *
46 * @param[in] r Local return value.
47 * @param[in] err_cmd Command to perform on any error.
48 * @param[in] val_opts Validation options.
49 * @param[in] label Label to go to on fatal error.
50 */
51#define LY_VAL_ERR_GOTO(r, err_cmd, val_opts, label) \
52 if (r) { \
53 err_cmd; \
54 if ((r != LY_EVALID) || !(val_opts & LYD_VALIDATE_MULTI_ERROR)) { \
55 goto label; \
56 } \
57 }
58
Michal Vaskoa6669ba2020-08-06 16:14:26 +020059LY_ERR
Michal Vasko8104fd42020-07-13 11:09:51 +020060lyd_val_diff_add(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_node **diff)
61{
62 LY_ERR ret = LY_SUCCESS;
63 struct lyd_node *new_diff = NULL;
Michal Vasko81bc5512020-11-13 18:05:18 +010064 const struct lyd_node *prev_inst;
Michal Vaskoe78faec2021-04-08 17:24:43 +020065 char *key = NULL, *value = NULL, *position = NULL;
Michal Vasko81bc5512020-11-13 18:05:18 +010066 size_t buflen = 0, bufused = 0;
Michal Vaskoe78faec2021-04-08 17:24:43 +020067 uint32_t pos;
Michal Vasko8104fd42020-07-13 11:09:51 +020068
69 assert((op == LYD_DIFF_OP_DELETE) || (op == LYD_DIFF_OP_CREATE));
70
Michal Vasko81bc5512020-11-13 18:05:18 +010071 if ((op == LYD_DIFF_OP_CREATE) && lysc_is_userordered(node->schema)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +020072 if (lysc_is_dup_inst_list(node->schema)) {
73 pos = lyd_list_pos(node);
Michal Vasko81bc5512020-11-13 18:05:18 +010074
Michal Vaskoe78faec2021-04-08 17:24:43 +020075 /* generate position meta */
76 if (pos > 1) {
77 if (asprintf(&position, "%" PRIu32, pos - 1) == -1) {
78 LOGMEM(LYD_CTX(node));
79 ret = LY_EMEM;
80 goto cleanup;
81 }
Michal Vasko81bc5512020-11-13 18:05:18 +010082 } else {
Michal Vaskoe78faec2021-04-08 17:24:43 +020083 position = strdup("");
84 LY_CHECK_ERR_GOTO(!position, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
Michal Vasko81bc5512020-11-13 18:05:18 +010085 }
86 } else {
Michal Vaskoe78faec2021-04-08 17:24:43 +020087 if (node->prev->next && (node->prev->schema == node->schema)) {
88 prev_inst = node->prev;
Michal Vasko81bc5512020-11-13 18:05:18 +010089 } else {
Michal Vaskoe78faec2021-04-08 17:24:43 +020090 /* first instance */
91 prev_inst = NULL;
92 }
93
94 if (node->schema->nodetype == LYS_LIST) {
95 /* generate key meta */
96 if (prev_inst) {
97 LY_CHECK_GOTO(ret = lyd_path_list_predicate(prev_inst, &key, &buflen, &bufused, 0), cleanup);
98 } else {
99 key = strdup("");
100 LY_CHECK_ERR_GOTO(!key, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
101 }
102 } else {
103 /* generate value meta */
104 if (prev_inst) {
Radek Krejci6d5ba0c2021-04-26 07:49:59 +0200105 value = strdup(lyd_get_value(prev_inst));
Michal Vaskoe78faec2021-04-08 17:24:43 +0200106 LY_CHECK_ERR_GOTO(!value, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
107 } else {
108 value = strdup("");
109 LY_CHECK_ERR_GOTO(!value, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
110 }
Michal Vasko81bc5512020-11-13 18:05:18 +0100111 }
112 }
113 }
114
Michal Vasko8104fd42020-07-13 11:09:51 +0200115 /* create new diff tree */
Michal Vaskoe78faec2021-04-08 17:24:43 +0200116 LY_CHECK_GOTO(ret = lyd_diff_add(node, op, NULL, NULL, key, value, position, NULL, NULL, &new_diff), cleanup);
Michal Vasko8104fd42020-07-13 11:09:51 +0200117
118 /* merge into existing diff */
Michal Vaskoc0e58e82020-11-11 19:04:33 +0100119 ret = lyd_diff_merge_all(diff, new_diff, 0);
Michal Vasko8104fd42020-07-13 11:09:51 +0200120
Michal Vasko81bc5512020-11-13 18:05:18 +0100121cleanup:
Michal Vasko8104fd42020-07-13 11:09:51 +0200122 lyd_free_tree(new_diff);
Michal Vasko81bc5512020-11-13 18:05:18 +0100123 free(key);
124 free(value);
Michal Vaskoe78faec2021-04-08 17:24:43 +0200125 free(position);
Michal Vasko8104fd42020-07-13 11:09:51 +0200126 return ret;
127}
128
129/**
Michal Vaskobd4db892020-11-23 16:58:20 +0100130 * @brief Evaluate all relevant "when" conditions of a node.
Michal Vaskocde73ac2019-11-14 16:10:27 +0100131 *
Michal Vaskobd4db892020-11-23 16:58:20 +0100132 * @param[in] tree Data tree.
133 * @param[in] node Node whose relevant when conditions will be evaluated.
134 * @param[in] schema Schema node of @p node. It may not be possible to use directly if @p node is opaque.
Michal Vasko976ec432021-12-06 15:42:22 +0100135 * @param[in] xpath_options Additional XPath options to use.
Michal Vaskobd4db892020-11-23 16:58:20 +0100136 * @param[out] disabled First when that evaluated false, if any.
137 * @return LY_SUCCESS on success.
138 * @return LY_EINCOMPLETE if a referenced node does not have its when evaluated.
139 * @return LY_ERR value on error.
Michal Vaskocde73ac2019-11-14 16:10:27 +0100140 */
141static LY_ERR
Michal Vaskobd4db892020-11-23 16:58:20 +0100142lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node, const struct lysc_node *schema,
Michal Vasko976ec432021-12-06 15:42:22 +0100143 uint32_t xpath_options, const struct lysc_when **disabled)
Michal Vaskocde73ac2019-11-14 16:10:27 +0100144{
Michal Vaskod027f382023-02-10 09:13:25 +0100145 LY_ERR r;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100146 const struct lyd_node *ctx_node;
147 struct lyxp_set xp_set;
Michal Vaskobd4db892020-11-23 16:58:20 +0100148 LY_ARRAY_COUNT_TYPE u;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100149
Michal Vaskobd4db892020-11-23 16:58:20 +0100150 assert(!node->schema || (node->schema == schema));
Michal Vaskocde73ac2019-11-14 16:10:27 +0100151
Michal Vaskobd4db892020-11-23 16:58:20 +0100152 *disabled = NULL;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100153
Michal Vaskobd4db892020-11-23 16:58:20 +0100154 do {
Radek Krejci9a3823e2021-01-27 20:26:46 +0100155 const struct lysc_when *when;
156 struct lysc_when **when_list = lysc_node_when(schema);
Michal Vasko26bbb272022-08-02 14:54:33 +0200157
Radek Krejci9a3823e2021-01-27 20:26:46 +0100158 LY_ARRAY_FOR(when_list, u) {
159 when = when_list[u];
Michal Vaskocde73ac2019-11-14 16:10:27 +0100160
Michal Vaskobd4db892020-11-23 16:58:20 +0100161 /* get context node */
162 if (when->context == schema) {
163 ctx_node = node;
164 } else {
165 assert((!when->context && !node->parent) || (when->context == node->parent->schema));
Michal Vasko9e685082021-01-29 14:49:09 +0100166 ctx_node = lyd_parent(node);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100167 }
Michal Vaskobd4db892020-11-23 16:58:20 +0100168
169 /* evaluate when */
170 memset(&xp_set, 0, sizeof xp_set);
Michal Vaskod027f382023-02-10 09:13:25 +0100171 r = lyxp_eval(LYD_CTX(node), when->cond, schema->module, LY_VALUE_SCHEMA_RESOLVED, when->prefixes,
Michal Vaskoa3e92bc2022-07-29 14:56:23 +0200172 ctx_node, ctx_node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_options);
Michal Vaskobd4db892020-11-23 16:58:20 +0100173 lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
174
175 /* return error or LY_EINCOMPLETE for dependant unresolved when */
Michal Vaskod027f382023-02-10 09:13:25 +0100176 LY_CHECK_RET(r);
Michal Vaskobd4db892020-11-23 16:58:20 +0100177
178 if (!xp_set.val.bln) {
179 /* false when */
180 *disabled = when;
181 return LY_SUCCESS;
Michal Vasko8104fd42020-07-13 11:09:51 +0200182 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100183 }
Michal Vaskobd4db892020-11-23 16:58:20 +0100184
185 schema = schema->parent;
186 } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
187
188 return LY_SUCCESS;
189}
190
191/**
Michal Vasko64eb14a2023-11-20 13:49:47 +0100192 * @brief Properly delete a node as part of auto-delete validation tasks.
193 *
194 * @param[in,out] first First sibling, is updated if needed.
195 * @param[in] del Node instance to delete.
196 * @param[in] mod Module of the siblings, NULL for nested siblings.
Michal Vaskoa7e92ec2023-11-21 09:18:39 +0100197 * @param[in] np_cont_diff Whether to put NP container into diff or only its children.
Michal Vasko64eb14a2023-11-20 13:49:47 +0100198 * @param[in,out] node Optional current iteration node, update it if it is deleted.
199 * @param[in,out] node_when Optional set with nodes with "when" conditions, may be removed from.
Michal Vasko7a8029e2024-07-17 08:35:50 +0200200 * @param[in,out] node_types Optional set with unresolved type nodes, may be removed from.
Michal Vasko64eb14a2023-11-20 13:49:47 +0100201 * @param[in,out] diff Validation diff.
202 * @return 1 if @p node auto-deleted and updated to its next sibling.
203 * @return 0 if @p node was not auto-deleted.
204 */
205static ly_bool
206lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, const struct lys_module *mod,
Michal Vasko7a8029e2024-07-17 08:35:50 +0200207 int np_cont_diff, struct lyd_node **node, struct ly_set *node_when, struct ly_set *node_types, struct lyd_node **diff)
Michal Vasko64eb14a2023-11-20 13:49:47 +0100208{
209 struct lyd_node *iter;
210 ly_bool node_autodel = 0;
211 uint32_t idx;
212
213 /* update pointers */
214 lyd_del_move_root(first, del, mod);
215 if (node && (del == *node)) {
216 *node = (*node)->next;
217 node_autodel = 1;
218 }
219
220 if (diff) {
221 /* add into diff */
Michal Vaskoa7e92ec2023-11-21 09:18:39 +0100222 if (!np_cont_diff && (del->schema->nodetype == LYS_CONTAINER) && !(del->schema->flags & LYS_PRESENCE)) {
Michal Vasko64eb14a2023-11-20 13:49:47 +0100223 /* we do not want to track NP container changes, but remember any removed children */
224 LY_LIST_FOR(lyd_child(del), iter) {
225 lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
226 }
227 } else {
228 lyd_val_diff_add(del, LYD_DIFF_OP_DELETE, diff);
229 }
230 }
231
Michal Vasko7a8029e2024-07-17 08:35:50 +0200232 if (node_when && node_when->count) {
233 /* remove nested from node_when set */
234 LYD_TREE_DFS_BEGIN(del, iter) {
235 if ((del != iter) && ly_set_contains(node_when, iter, &idx)) {
236 ly_set_rm_index(node_when, idx, NULL);
237 }
238 LYD_TREE_DFS_END(del, iter);
239 }
240 }
241
Michal Vasko64eb14a2023-11-20 13:49:47 +0100242 if (node_types && node_types->count) {
243 /* remove from node_types set */
244 LYD_TREE_DFS_BEGIN(del, iter) {
245 if (ly_set_contains(node_types, iter, &idx)) {
246 ly_set_rm_index(node_types, idx, NULL);
247 }
248 LYD_TREE_DFS_END(del, iter);
249 }
250 }
251
252 /* free */
253 lyd_free_tree(del);
254
255 return node_autodel;
256}
257
258/**
Michal Vaskobd4db892020-11-23 16:58:20 +0100259 * @brief Evaluate when conditions of collected unres nodes.
260 *
261 * @param[in,out] tree Data tree, is updated if some nodes are autodeleted.
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100262 * @param[in] mod Module of the @p tree to take into consideration when deleting @p tree and moving it.
263 * If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
264 * the first top-level sibling.
Michal Vaskobd4db892020-11-23 16:58:20 +0100265 * @param[in] node_when Set with nodes with "when" conditions.
Michal Vaskod027f382023-02-10 09:13:25 +0100266 * @param[in] val_opts Validation options.
Michal Vasko976ec432021-12-06 15:42:22 +0100267 * @param[in] xpath_options Additional XPath options to use.
Michal Vasko27d2b1b2021-07-19 15:20:02 +0200268 * @param[in,out] node_types Set with nodes with unresolved types, remove any with false "when" parents.
Michal Vaskobd4db892020-11-23 16:58:20 +0100269 * @param[in,out] diff Validation diff.
270 * @return LY_SUCCESS on success.
271 * @return LY_ERR value on error.
272 */
273static LY_ERR
Michal Vaskod027f382023-02-10 09:13:25 +0100274lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when, uint32_t val_opts,
Michal Vasko976ec432021-12-06 15:42:22 +0100275 uint32_t xpath_options, struct ly_set *node_types, struct lyd_node **diff)
Michal Vaskobd4db892020-11-23 16:58:20 +0100276{
Michal Vaskod027f382023-02-10 09:13:25 +0100277 LY_ERR rc = LY_SUCCESS, r;
Michal Vasko7a8029e2024-07-17 08:35:50 +0200278 uint32_t i, count;
Michal Vaskobd4db892020-11-23 16:58:20 +0100279 const struct lysc_when *disabled;
Michal Vasko64eb14a2023-11-20 13:49:47 +0100280 struct lyd_node *node = NULL;
Michal Vaskobd4db892020-11-23 16:58:20 +0100281
282 if (!node_when->count) {
283 return LY_SUCCESS;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100284 }
285
Michal Vaskobd4db892020-11-23 16:58:20 +0100286 i = node_when->count;
287 do {
288 --i;
289 node = node_when->dnodes[i];
Michal Vasko7a266772024-01-23 11:02:38 +0100290 LOG_LOCSET(node->schema, node);
Michal Vaskobd4db892020-11-23 16:58:20 +0100291
292 /* evaluate all when expressions that affect this node's existence */
Michal Vasko6f0c5c72022-08-05 15:28:14 +0200293 r = lyd_validate_node_when(*tree, node, node->schema, xpath_options, &disabled);
294 if (!r) {
Michal Vaskobd4db892020-11-23 16:58:20 +0100295 if (disabled) {
296 /* when false */
297 if (node->flags & LYD_WHEN_TRUE) {
298 /* autodelete */
Michal Vasko7a8029e2024-07-17 08:35:50 +0200299 count = node_when->count;
300 lyd_validate_autodel_node_del(tree, node, mod, 1, NULL, node_when, node_types, diff);
301 if (count > node_when->count) {
302 /* nested nodes removed, we lost the index */
303 ly_set_contains(node_when, node, &i);
304 }
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100305 } else if (val_opts & LYD_VALIDATE_OPERATIONAL) {
306 /* only a warning */
307 LOGWRN(LYD_CTX(node), "When condition \"%s\" not satisfied.", disabled->cond->expr);
Michal Vaskobd4db892020-11-23 16:58:20 +0100308 } else {
309 /* invalid data */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100310 LOGVAL(LYD_CTX(node), LY_VCODE_NOWHEN, disabled->cond->expr);
Michal Vaskod027f382023-02-10 09:13:25 +0100311 r = LY_EVALID;
312 LY_VAL_ERR_GOTO(r, rc = r, val_opts, error);
Michal Vaskobd4db892020-11-23 16:58:20 +0100313 }
314 } else {
315 /* when true */
316 node->flags |= LYD_WHEN_TRUE;
317 }
318
Michal Vasko413af592021-12-13 11:50:51 +0100319 /* remove this node from the set keeping the order, its when was resolved */
320 ly_set_rm_index_ordered(node_when, i, NULL);
Michal Vasko6f0c5c72022-08-05 15:28:14 +0200321 } else if (r != LY_EINCOMPLETE) {
Michal Vaskobd4db892020-11-23 16:58:20 +0100322 /* error */
Michal Vaskod027f382023-02-10 09:13:25 +0100323 LY_VAL_ERR_GOTO(r, rc = r, val_opts, error);
Michal Vaskobd4db892020-11-23 16:58:20 +0100324 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100325
Michal Vasko7a266772024-01-23 11:02:38 +0100326 LOG_LOCBACK(1, 1);
Michal Vaskobd4db892020-11-23 16:58:20 +0100327 } while (i);
328
Michal Vaskod027f382023-02-10 09:13:25 +0100329 return rc;
Radek Krejci2efc45b2020-12-22 16:25:44 +0100330
331error:
Michal Vasko7a266772024-01-23 11:02:38 +0100332 LOG_LOCBACK(1, 1);
Michal Vasko6f0c5c72022-08-05 15:28:14 +0200333 return rc;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100334}
335
Radek Krejci4f2e3e52021-03-30 14:20:28 +0200336LY_ERR
Michal Vaskofbbea932022-06-07 11:00:55 +0200337lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum lyd_type data_type, struct ly_set *node_when,
Michal Vasko135719f2022-08-25 12:18:17 +0200338 uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_node,
339 struct ly_set *ext_val, uint32_t val_opts, struct lyd_node **diff)
Michal Vaskocde73ac2019-11-14 16:10:27 +0100340{
Michal Vaskod027f382023-02-10 09:13:25 +0100341 LY_ERR r, rc = LY_SUCCESS;
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200342 uint32_t i;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100343
Michal Vaskoddd76592022-01-17 13:34:48 +0100344 if (ext_val && ext_val->count) {
345 /* first validate parsed extension data */
346 i = ext_val->count;
347 do {
348 --i;
349
350 struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
351
352 /* validate extension data */
Michal Vaskod027f382023-02-10 09:13:25 +0100353 r = ext_v->ext->def->plugin->validate(ext_v->ext, ext_v->sibling, *tree, data_type, val_opts, diff);
354 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoddd76592022-01-17 13:34:48 +0100355
356 /* remove this item from the set */
Michal Vasko8cc3f662022-03-29 11:25:51 +0200357 ly_set_rm_index(ext_val, i, free);
Michal Vaskoddd76592022-01-17 13:34:48 +0100358 } while (i);
359 }
360
Michal Vasko135719f2022-08-25 12:18:17 +0200361 if (ext_node && ext_node->count) {
362 /* validate data nodes with extension instances */
363 i = ext_node->count;
364 do {
365 --i;
366
367 struct lyd_ctx_ext_node *ext_n = ext_node->objs[i];
368
369 /* validate the node */
Michal Vaskod027f382023-02-10 09:13:25 +0100370 r = ext_n->ext->def->plugin->node(ext_n->ext, ext_n->node, val_opts);
371 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko135719f2022-08-25 12:18:17 +0200372
373 /* remove this item from the set */
374 ly_set_rm_index(ext_node, i, free);
375 } while (i);
376 }
377
Michal Vaskob1b5c262020-03-05 14:29:47 +0100378 if (node_when) {
379 /* evaluate all when conditions */
380 uint32_t prev_count;
Michal Vasko26bbb272022-08-02 14:54:33 +0200381
Michal Vaskob1b5c262020-03-05 14:29:47 +0100382 do {
383 prev_count = node_when->count;
Michal Vaskod027f382023-02-10 09:13:25 +0100384 r = lyd_validate_unres_when(tree, mod, node_when, val_opts, when_xp_opts, node_types, diff);
385 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
386
Radek Krejci0f969882020-08-21 16:56:47 +0200387 /* there must have been some when conditions resolved */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100388 } while (prev_count > node_when->count);
Michal Vaskocde73ac2019-11-14 16:10:27 +0100389
Michal Vaskob1b5c262020-03-05 14:29:47 +0100390 /* there could have been no cyclic when dependencies, checked during compilation */
Michal Vasko0b877d52023-11-20 13:50:08 +0100391 assert(!node_when->count || ((rc == LY_EVALID) && (val_opts & LYD_VALIDATE_MULTI_ERROR)));
Michal Vaskob1b5c262020-03-05 14:29:47 +0100392 }
393
394 if (node_types && node_types->count) {
395 /* finish incompletely validated terminal values (traverse from the end for efficient set removal) */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200396 i = node_types->count;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100397 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200398 --i;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100399
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100400 struct lyd_node_term *node = node_types->objs[i];
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200401 struct lysc_type *type = ((struct lysc_node_leaf *)node->schema)->type;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100402
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200403 /* resolve the value of the node */
Michal Vasko7a266772024-01-23 11:02:38 +0100404 LOG_LOCSET(NULL, &node->node);
Michal Vaskod027f382023-02-10 09:13:25 +0100405 r = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree);
Michal Vasko7a266772024-01-23 11:02:38 +0100406 LOG_LOCBACK(0, 1);
Michal Vaskod027f382023-02-10 09:13:25 +0100407 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100408
409 /* remove this node from the set */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200410 ly_set_rm_index(node_types, i, NULL);
411 } while (i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100412 }
413
Michal Vasko9f96a052020-03-10 09:41:45 +0100414 if (meta_types && meta_types->count) {
415 /* ... and metadata values */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200416 i = meta_types->count;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100417 do {
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200418 --i;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100419
Michal Vasko14ed9cd2021-01-28 14:16:25 +0100420 struct lyd_meta *meta = meta_types->objs[i];
Michal Vasko193dacd2022-10-13 08:43:05 +0200421 struct lysc_type *type;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100422
Michal Vasko9f96a052020-03-10 09:41:45 +0100423 /* validate and store the value of the metadata */
Michal Vaskofbd037c2022-11-08 10:34:20 +0100424 lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
Michal Vaskod027f382023-02-10 09:13:25 +0100425 r = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree);
426 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100427
428 /* remove this attr from the set */
Radek Krejci7eb54ba2020-05-18 16:30:04 +0200429 ly_set_rm_index(meta_types, i, NULL);
430 } while (i);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100431 }
Michal Vaskocde73ac2019-11-14 16:10:27 +0100432
Michal Vaskod027f382023-02-10 09:13:25 +0100433cleanup:
434 return rc;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100435}
436
Michal Vaskobb844672020-07-03 11:06:12 +0200437/**
438 * @brief Validate instance duplication.
439 *
440 * @param[in] first First sibling to search in.
441 * @param[in] node Data node instance to check.
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100442 * @param[in] val_opts Validation options.
Michal Vaskobb844672020-07-03 11:06:12 +0200443 * @return LY_ERR value.
444 */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100445static LY_ERR
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100446lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *node, uint32_t val_opts)
Michal Vaskocde73ac2019-11-14 16:10:27 +0100447{
Michal Vasko04a89c22023-10-03 14:03:09 +0200448 struct lyd_node **match_p, *match;
Radek Krejci857189e2020-09-01 13:26:36 +0200449 ly_bool fail = 0;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100450
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100451 assert(node->flags & LYD_NEW);
452
Michal Vaskod6c18af2021-02-12 12:07:31 +0100453 /* key-less list or non-configuration leaf-list */
Michal Vaskoe78faec2021-04-08 17:24:43 +0200454 if (lysc_is_dup_inst_list(node->schema)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100455 /* duplicate instances allowed */
456 return LY_SUCCESS;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100457 }
458
Michal Vaskob1b5c262020-03-05 14:29:47 +0100459 /* find exactly the same next instance using hashes if possible */
460 if (node->parent && node->parent->children_ht) {
Michal Vasko04a89c22023-10-03 14:03:09 +0200461 lyd_find_sibling_first(first, node, &match);
462 assert(match);
463
464 if (match != node) {
465 fail = 1;
466 } else if (!lyht_find_next(node->parent->children_ht, &node, node->hash, (void **)&match_p)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100467 fail = 1;
468 }
469 } else {
Michal Vaskod989ba02020-08-24 10:59:24 +0200470 for ( ; first; first = first->next) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100471 if (first == node) {
472 continue;
473 }
474
475 if (node->schema->nodetype & (LYD_NODE_ANY | LYS_LEAF)) {
476 if (first->schema == node->schema) {
477 fail = 1;
478 break;
479 }
Michal Vasko8f359bf2020-07-28 10:41:15 +0200480 } else if (!lyd_compare_single(first, node, 0)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +0100481 fail = 1;
482 break;
483 }
484 }
485 }
486
487 if (fail) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100488 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (val_opts & LYD_VALIDATE_OPERATIONAL)) {
489 /* only a warning */
Michal Vasko7a266772024-01-23 11:02:38 +0100490 LOG_LOCSET(NULL, node);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100491 LOGWRN(node->schema->module->ctx, "Duplicate instance of \"%s\".", node->schema->name);
Michal Vasko7a266772024-01-23 11:02:38 +0100492 LOG_LOCBACK(0, 1);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100493 } else {
Michal Vasko7a266772024-01-23 11:02:38 +0100494 LOG_LOCSET(NULL, node);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100495 LOGVAL(node->schema->module->ctx, LY_VCODE_DUP, node->schema->name);
Michal Vasko7a266772024-01-23 11:02:38 +0100496 LOG_LOCBACK(0, 1);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100497 return LY_EVALID;
498 }
Michal Vaskob1b5c262020-03-05 14:29:47 +0100499 }
500 return LY_SUCCESS;
Michal Vaskocde73ac2019-11-14 16:10:27 +0100501}
502
Michal Vaskobb844672020-07-03 11:06:12 +0200503/**
504 * @brief Validate multiple case data existence with possible autodelete.
505 *
506 * @param[in,out] first First sibling to search in, is updated if needed.
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100507 * @param[in] mod Module of the siblings, NULL for nested siblings.
Michal Vaskobb844672020-07-03 11:06:12 +0200508 * @param[in] choic Choice node whose cases to check.
Michal Vasko8104fd42020-07-13 11:09:51 +0200509 * @param[in,out] diff Validation diff.
Michal Vaskobb844672020-07-03 11:06:12 +0200510 * @return LY_ERR value.
511 */
Michal Vaskocde73ac2019-11-14 16:10:27 +0100512static LY_ERR
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100513lyd_validate_cases(struct lyd_node **first, const struct lys_module *mod, const struct lysc_node_choice *choic,
514 struct lyd_node **diff)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100515{
516 const struct lysc_node *scase, *iter, *old_case = NULL, *new_case = NULL;
517 struct lyd_node *match, *to_del;
Radek Krejci857189e2020-09-01 13:26:36 +0200518 ly_bool found;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100519
Michal Vasko7a266772024-01-23 11:02:38 +0100520 LOG_LOCSET(&choic->node, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521
Michal Vaskob1b5c262020-03-05 14:29:47 +0100522 LY_LIST_FOR((struct lysc_node *)choic->cases, scase) {
523 found = 0;
524 iter = NULL;
525 match = NULL;
526 while ((match = lys_getnext_data(match, *first, &iter, scase, NULL))) {
527 if (match->flags & LYD_NEW) {
528 /* a new case data found, nothing more to look for */
529 found = 2;
530 break;
531 } else {
532 /* and old case data found */
533 if (found == 0) {
534 found = 1;
535 }
536 }
537 }
538
539 if (found == 1) {
540 /* there should not be 2 old cases */
541 if (old_case) {
542 /* old data from 2 cases */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100543 LOGVAL(choic->module->ctx, LY_VCODE_DUPCASE, old_case->name, scase->name);
Michal Vasko7a266772024-01-23 11:02:38 +0100544 LOG_LOCBACK(1, 0);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100545 return LY_EVALID;
546 }
547
548 /* remember an old existing case */
549 old_case = scase;
550 } else if (found == 2) {
551 if (new_case) {
552 /* new data from 2 cases */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100553 LOGVAL(choic->module->ctx, LY_VCODE_DUPCASE, new_case->name, scase->name);
Michal Vasko7a266772024-01-23 11:02:38 +0100554 LOG_LOCBACK(1, 0);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100555 return LY_EVALID;
556 }
557
558 /* remember a new existing case */
559 new_case = scase;
560 }
561 }
562
Michal Vasko7a266772024-01-23 11:02:38 +0100563 LOG_LOCBACK(1, 0);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100564
Michal Vaskob1b5c262020-03-05 14:29:47 +0100565 if (old_case && new_case) {
566 /* auto-delete old case */
567 iter = NULL;
568 match = NULL;
569 to_del = NULL;
570 while ((match = lys_getnext_data(match, *first, &iter, old_case, NULL))) {
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100571 lyd_del_move_root(first, to_del, mod);
572
Michal Vasko8104fd42020-07-13 11:09:51 +0200573 /* free previous node */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100574 lyd_free_tree(to_del);
Michal Vasko8104fd42020-07-13 11:09:51 +0200575 if (diff) {
576 /* add into diff */
577 LY_CHECK_RET(lyd_val_diff_add(match, LYD_DIFF_OP_DELETE, diff));
578 }
Michal Vaskob1b5c262020-03-05 14:29:47 +0100579 to_del = match;
580 }
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100581 lyd_del_move_root(first, to_del, mod);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100582 lyd_free_tree(to_del);
583 }
584
585 return LY_SUCCESS;
586}
587
Michal Vaskobb844672020-07-03 11:06:12 +0200588/**
589 * @brief Check whether a schema node can have some default values (true for NP containers as well).
590 *
591 * @param[in] schema Schema node to check.
592 * @return non-zero if yes,
593 * @return 0 otherwise.
594 */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100595static int
596lyd_val_has_default(const struct lysc_node *schema)
597{
598 switch (schema->nodetype) {
599 case LYS_LEAF:
600 if (((struct lysc_node_leaf *)schema)->dflt) {
601 return 1;
602 }
603 break;
604 case LYS_LEAFLIST:
605 if (((struct lysc_node_leaflist *)schema)->dflts) {
606 return 1;
607 }
608 break;
609 case LYS_CONTAINER:
610 if (!(schema->flags & LYS_PRESENCE)) {
611 return 1;
612 }
613 break;
614 default:
615 break;
616 }
617
618 return 0;
619}
620
Michal Vaskobb844672020-07-03 11:06:12 +0200621/**
Michal Vasko42266212022-12-01 08:33:11 +0100622 * @brief Auto-delete leaf-list default instances to prevent validation errors.
Michal Vaskobb844672020-07-03 11:06:12 +0200623 *
624 * @param[in,out] first First sibling to search in, is updated if needed.
Michal Vasko42266212022-12-01 08:33:11 +0100625 * @param[in,out] node New data node instance to check, is updated if auto-deleted.
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100626 * @param[in] mod Module of the siblings, NULL for nested siblings.
Michal Vasko8104fd42020-07-13 11:09:51 +0200627 * @param[in,out] diff Validation diff.
Michal Vasko42266212022-12-01 08:33:11 +0100628 * @return 1 if @p node auto-deleted and updated to its next sibling.
629 * @return 0 if @p node was not auto-deleted.
Michal Vaskobb844672020-07-03 11:06:12 +0200630 */
Michal Vasko42266212022-12-01 08:33:11 +0100631static ly_bool
632lyd_validate_autodel_leaflist_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
633 struct lyd_node **diff)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100634{
Michal Vasko42266212022-12-01 08:33:11 +0100635 const struct lysc_node *schema;
636 struct lyd_node *iter, *next;
637 ly_bool found = 0, node_autodel = 0;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100638
Michal Vasko42266212022-12-01 08:33:11 +0100639 assert((*node)->flags & LYD_NEW);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100640
Michal Vasko42266212022-12-01 08:33:11 +0100641 schema = (*node)->schema;
642 assert(schema->nodetype == LYS_LEAFLIST);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100643
Michal Vasko42266212022-12-01 08:33:11 +0100644 /* check whether there is any explicit instance */
645 LYD_LIST_FOR_INST(*first, schema, iter) {
646 if (!(iter->flags & LYD_DEFAULT)) {
647 found = 1;
648 break;
649 }
650 }
651 if (!found) {
652 /* no explicit instance, keep defaults as they are */
653 return 0;
654 }
655
656 LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
657 if (iter->flags & LYD_DEFAULT) {
658 /* default instance found, remove it */
Michal Vasko7a8029e2024-07-17 08:35:50 +0200659 if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
Michal Vasko42266212022-12-01 08:33:11 +0100660 node_autodel = 1;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100661 }
Michal Vaskob1b5c262020-03-05 14:29:47 +0100662 }
663 }
Michal Vasko42266212022-12-01 08:33:11 +0100664
665 return node_autodel;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100666}
667
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100668/**
Michal Vasko42266212022-12-01 08:33:11 +0100669 * @brief Auto-delete container or leaf default instances to prevent validation errors.
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100670 *
671 * @param[in,out] first First sibling to search in, is updated if needed.
Michal Vasko42266212022-12-01 08:33:11 +0100672 * @param[in,out] node New data node instance to check, is updated if auto-deleted.
Michal Vaskod3bb12f2020-12-04 14:33:09 +0100673 * @param[in] mod Module of the siblings, NULL for nested siblings.
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100674 * @param[in,out] diff Validation diff.
Michal Vasko42266212022-12-01 08:33:11 +0100675 * @return 1 if @p node auto-deleted and updated to its next sibling.
676 * @return 0 if @p node was not auto-deleted.
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100677 */
Michal Vasko42266212022-12-01 08:33:11 +0100678static ly_bool
679lyd_validate_autodel_cont_leaf_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
680 struct lyd_node **diff)
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100681{
Michal Vasko42266212022-12-01 08:33:11 +0100682 const struct lysc_node *schema;
683 struct lyd_node *iter, *next;
684 ly_bool found = 0, node_autodel = 0;
685
686 assert((*node)->flags & LYD_NEW);
687
688 schema = (*node)->schema;
689 assert(schema->nodetype & (LYS_LEAF | LYS_CONTAINER));
690
691 /* check whether there is any explicit instance */
692 LYD_LIST_FOR_INST(*first, schema, iter) {
693 if (!(iter->flags & LYD_DEFAULT)) {
694 found = 1;
695 break;
696 }
697 }
698
699 if (found) {
700 /* remove all default instances */
701 LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
702 if (iter->flags & LYD_DEFAULT) {
703 /* default instance, remove it */
Michal Vasko7a8029e2024-07-17 08:35:50 +0200704 if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
Michal Vasko42266212022-12-01 08:33:11 +0100705 node_autodel = 1;
706 }
707 }
708 }
709 } else {
710 /* remove a single old default instance, if any */
711 LYD_LIST_FOR_INST(*first, schema, iter) {
712 if ((iter->flags & LYD_DEFAULT) && !(iter->flags & LYD_NEW)) {
713 /* old default instance, remove it */
Michal Vasko7a8029e2024-07-17 08:35:50 +0200714 if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
Michal Vasko42266212022-12-01 08:33:11 +0100715 node_autodel = 1;
716 }
717 break;
718 }
719 }
720 }
721
722 return node_autodel;
723}
724
725/**
726 * @brief Auto-delete leftover default nodes of deleted cases (that have no existing explicit data).
727 *
728 * @param[in,out] first First sibling to search in, is updated if needed.
729 * @param[in,out] node Default data node instance to check.
730 * @param[in] mod Module of the siblings, NULL for nested siblings.
731 * @param[in,out] diff Validation diff.
732 * @return 1 if @p node auto-deleted and updated to its next sibling.
733 * @return 0 if @p node was not auto-deleted.
734 */
735static ly_bool
736lyd_validate_autodel_case_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
737 struct lyd_node **diff)
738{
739 const struct lysc_node *schema;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100740 struct lysc_node_choice *choic;
741 struct lyd_node *iter = NULL;
742 const struct lysc_node *slast = NULL;
Michal Vasko42266212022-12-01 08:33:11 +0100743 ly_bool node_autodel = 0;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100744
Michal Vasko42266212022-12-01 08:33:11 +0100745 assert((*node)->flags & LYD_DEFAULT);
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100746
Michal Vasko42266212022-12-01 08:33:11 +0100747 schema = (*node)->schema;
748
749 if (!schema->parent || (schema->parent->nodetype != LYS_CASE)) {
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100750 /* the default node is not a descendant of a case */
Michal Vasko42266212022-12-01 08:33:11 +0100751 return 0;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100752 }
753
Michal Vasko42266212022-12-01 08:33:11 +0100754 choic = (struct lysc_node_choice *)schema->parent->parent;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100755 assert(choic->nodetype == LYS_CHOICE);
756
Michal Vasko42266212022-12-01 08:33:11 +0100757 if (choic->dflt && (choic->dflt == (struct lysc_node_case *)schema->parent)) {
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100758 /* data of a default case, keep them */
Michal Vasko42266212022-12-01 08:33:11 +0100759 return 0;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100760 }
761
762 /* try to find an explicit node of the case */
Michal Vasko42266212022-12-01 08:33:11 +0100763 while ((iter = lys_getnext_data(iter, *first, &slast, schema->parent, NULL))) {
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100764 if (!(iter->flags & LYD_DEFAULT)) {
765 break;
766 }
767 }
768
769 if (!iter) {
770 /* there are only default nodes of the case meaning it does not exist and neither should any default nodes
771 * of the case, remove this one default node */
Michal Vasko7a8029e2024-07-17 08:35:50 +0200772 if (lyd_validate_autodel_node_del(first, *node, mod, 0, node, NULL, NULL, diff)) {
Michal Vasko42266212022-12-01 08:33:11 +0100773 node_autodel = 1;
774 }
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100775 }
Michal Vasko42266212022-12-01 08:33:11 +0100776
777 return node_autodel;
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100778}
779
Michal Vasko17f76642021-08-03 17:01:30 +0200780/**
781 * @brief Validate new siblings in choices, recursively for nested choices.
782 *
783 * @param[in,out] first First sibling.
784 * @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
785 * @param[in] mod Module of the siblings, NULL for nested siblings.
Michal Vaskod027f382023-02-10 09:13:25 +0100786 * @param[in] val_opts Validation options.
Michal Vasko17f76642021-08-03 17:01:30 +0200787 * @param[in,out] diff Validation diff.
788 * @return LY_ERR value.
789 */
790static LY_ERR
791lyd_validate_choice_r(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
Michal Vaskod027f382023-02-10 09:13:25 +0100792 uint32_t val_opts, struct lyd_node **diff)
Michal Vaskob1b5c262020-03-05 14:29:47 +0100793{
Michal Vaskod027f382023-02-10 09:13:25 +0100794 LY_ERR r, rc = LY_SUCCESS;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100795 const struct lysc_node *snode = NULL;
796
Michal Vaskob1b5c262020-03-05 14:29:47 +0100797 while (*first && (snode = lys_getnext(snode, sparent, mod ? mod->compiled : NULL, LYS_GETNEXT_WITHCHOICE))) {
798 /* check case duplicites */
799 if (snode->nodetype == LYS_CHOICE) {
Michal Vaskod027f382023-02-10 09:13:25 +0100800 r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)snode, diff);
801 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko17f76642021-08-03 17:01:30 +0200802
803 /* check for nested choice */
Michal Vaskod027f382023-02-10 09:13:25 +0100804 r = lyd_validate_choice_r(first, snode, mod, val_opts, diff);
805 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100806 }
807 }
808
Michal Vaskod027f382023-02-10 09:13:25 +0100809cleanup:
810 return rc;
Michal Vasko17f76642021-08-03 17:01:30 +0200811}
812
813LY_ERR
814lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
Michal Vaskod027f382023-02-10 09:13:25 +0100815 uint32_t val_opts, struct lyd_node **diff)
Michal Vasko17f76642021-08-03 17:01:30 +0200816{
Michal Vaskod027f382023-02-10 09:13:25 +0100817 LY_ERR r, rc = LY_SUCCESS;
Michal Vasko42266212022-12-01 08:33:11 +0100818 struct lyd_node *node;
819 const struct lysc_node *last_dflt_schema = NULL;
Michal Vasko17f76642021-08-03 17:01:30 +0200820
821 assert(first && (sparent || mod));
822
823 /* validate choices */
Michal Vaskod027f382023-02-10 09:13:25 +0100824 r = lyd_validate_choice_r(first, sparent, mod, val_opts, diff);
825 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko17f76642021-08-03 17:01:30 +0200826
Michal Vasko42266212022-12-01 08:33:11 +0100827 node = *first;
828 while (node) {
Michal Vasko6a6e3082022-05-10 10:32:38 +0200829 if (!node->schema || (mod && (lyd_owner_module(node) != mod))) {
830 /* opaque node or all top-level data from this module checked */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100831 break;
832 }
833
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100834 if (!(node->flags & (LYD_NEW | LYD_DEFAULT))) {
835 /* check only new and default nodes */
Michal Vasko42266212022-12-01 08:33:11 +0100836 node = node->next;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100837 continue;
838 }
839
Michal Vasko42266212022-12-01 08:33:11 +0100840 if (lyd_val_has_default(node->schema) && (node->schema != last_dflt_schema) && (node->flags & LYD_NEW)) {
841 /* remove old default(s) of the new node if an explicit instance exists */
842 last_dflt_schema = node->schema;
843 if (node->schema->nodetype == LYS_LEAFLIST) {
844 if (lyd_validate_autodel_leaflist_dflt(first, &node, mod, diff)) {
845 continue;
846 }
847 } else {
848 if (lyd_validate_autodel_cont_leaf_dflt(first, &node, mod, diff)) {
849 continue;
850 }
851 }
852 }
Radek Krejci2efc45b2020-12-22 16:25:44 +0100853
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100854 if (node->flags & LYD_NEW) {
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100855 /* then check new node instance duplicities */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100856 r = lyd_validate_duplicates(*first, node, val_opts);
Michal Vaskod027f382023-02-10 09:13:25 +0100857 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +0100858
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100859 /* this node is valid */
860 node->flags &= ~LYD_NEW;
861 }
862
863 if (node->flags & LYD_DEFAULT) {
864 /* remove leftover default nodes from a no-longer existing case */
Michal Vasko42266212022-12-01 08:33:11 +0100865 if (lyd_validate_autodel_case_dflt(first, &node, mod, diff)) {
866 continue;
867 }
Michal Vaskodcacf2f2020-11-18 18:18:15 +0100868 }
Michal Vasko42266212022-12-01 08:33:11 +0100869
870 /* next iter */
871 node = node->next;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100872 }
873
Michal Vaskod027f382023-02-10 09:13:25 +0100874cleanup:
875 return rc;
Michal Vaskob1b5c262020-03-05 14:29:47 +0100876}
877
Michal Vaskobb844672020-07-03 11:06:12 +0200878/**
Michal Vaskobd4db892020-11-23 16:58:20 +0100879 * @brief Evaluate any "when" conditions of a non-existent data node with existing parent.
880 *
881 * @param[in] first First data sibling of the non-existing node.
882 * @param[in] parent Data parent of the non-existing node.
883 * @param[in] snode Schema node of the non-existing node.
884 * @param[out] disabled First when that evaluated false, if any.
885 * @return LY_ERR value.
886 */
887static LY_ERR
888lyd_validate_dummy_when(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
889 const struct lysc_when **disabled)
890{
Michal Vaskod027f382023-02-10 09:13:25 +0100891 LY_ERR rc = LY_SUCCESS;
Michal Vaskobd4db892020-11-23 16:58:20 +0100892 struct lyd_node *tree, *dummy = NULL;
Michal Vaskoa27245c2022-05-02 09:01:35 +0200893 uint32_t xp_opts;
Michal Vaskobd4db892020-11-23 16:58:20 +0100894
895 /* find root */
896 if (parent) {
897 tree = (struct lyd_node *)parent;
898 while (tree->parent) {
899 tree = lyd_parent(tree);
900 }
901 tree = lyd_first_sibling(tree);
902 } else {
Michal Vaskobd99b5e2022-04-29 11:15:47 +0200903 /* is the first sibling from the same module, but may not be the actual first */
904 tree = lyd_first_sibling(first);
Michal Vaskobd4db892020-11-23 16:58:20 +0100905 }
906
907 /* create dummy opaque node */
Michal Vaskod027f382023-02-10 09:13:25 +0100908 rc = lyd_new_opaq((struct lyd_node *)parent, snode->module->ctx, snode->name, NULL, NULL, snode->module->name, &dummy);
909 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskobd4db892020-11-23 16:58:20 +0100910
911 /* connect it if needed */
912 if (!parent) {
913 if (first) {
914 lyd_insert_sibling((struct lyd_node *)first, dummy, &tree);
915 } else {
916 assert(!tree);
917 tree = dummy;
918 }
919 }
920
Michal Vaskoa27245c2022-05-02 09:01:35 +0200921 /* explicitly specified accesible tree */
922 if (snode->flags & LYS_CONFIG_W) {
923 xp_opts = LYXP_ACCESS_TREE_CONFIG;
924 } else {
925 xp_opts = LYXP_ACCESS_TREE_ALL;
926 }
927
Michal Vaskobd4db892020-11-23 16:58:20 +0100928 /* evaluate all when */
Michal Vaskod027f382023-02-10 09:13:25 +0100929 rc = lyd_validate_node_when(tree, dummy, snode, xp_opts, disabled);
930 if (rc == LY_EINCOMPLETE) {
Michal Vaskobd4db892020-11-23 16:58:20 +0100931 /* all other when must be resolved by now */
932 LOGINT(snode->module->ctx);
Michal Vaskod027f382023-02-10 09:13:25 +0100933 rc = LY_EINT;
Michal Vaskobd4db892020-11-23 16:58:20 +0100934 goto cleanup;
Michal Vaskod027f382023-02-10 09:13:25 +0100935 } else if (rc) {
Michal Vaskobd4db892020-11-23 16:58:20 +0100936 /* error */
937 goto cleanup;
938 }
939
940cleanup:
941 lyd_free_tree(dummy);
Michal Vaskod027f382023-02-10 09:13:25 +0100942 return rc;
Michal Vaskobd4db892020-11-23 16:58:20 +0100943}
944
945/**
Michal Vaskobb844672020-07-03 11:06:12 +0200946 * @brief Validate mandatory node existence.
947 *
948 * @param[in] first First sibling to search in.
Michal Vaskobd4db892020-11-23 16:58:20 +0100949 * @param[in] parent Data parent.
Michal Vaskobb844672020-07-03 11:06:12 +0200950 * @param[in] snode Schema node to validate.
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100951 * @param[in] val_opts Validation options.
Michal Vaskobb844672020-07-03 11:06:12 +0200952 * @return LY_ERR value.
953 */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100954static LY_ERR
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100955lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
956 uint32_t val_opts)
Michal Vaskoa3881362020-01-21 15:57:35 +0100957{
Michal Vaskobd4db892020-11-23 16:58:20 +0100958 const struct lysc_when *disabled;
959
Michal Vaskoa3881362020-01-21 15:57:35 +0100960 if (snode->nodetype == LYS_CHOICE) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100961 /* some data of a choice case exist */
Michal Vaskob1b5c262020-03-05 14:29:47 +0100962 if (lys_getnext_data(NULL, first, NULL, snode, NULL)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100963 return LY_SUCCESS;
964 }
965 } else {
966 assert(snode->nodetype & (LYS_LEAF | LYS_CONTAINER | LYD_NODE_ANY));
Michal Vaskoa3881362020-01-21 15:57:35 +0100967
Michal Vaskob1b5c262020-03-05 14:29:47 +0100968 if (!lyd_find_sibling_val(first, snode, NULL, 0, NULL)) {
Michal Vasko9b368d32020-02-14 13:53:31 +0100969 /* data instance found */
970 return LY_SUCCESS;
Michal Vaskoa3881362020-01-21 15:57:35 +0100971 }
972 }
973
Michal Vaskobd4db892020-11-23 16:58:20 +0100974 disabled = NULL;
975 if (lysc_has_when(snode)) {
976 /* if there are any when conditions, they must be true for a validation error */
977 LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, &disabled));
978 }
979
980 if (!disabled) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100981 if (val_opts & LYD_VALIDATE_OPERATIONAL) {
982 /* only a warning */
Michal Vasko7a266772024-01-23 11:02:38 +0100983 LOG_LOCSET(parent ? NULL : snode, parent);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100984 if (snode->nodetype == LYS_CHOICE) {
985 LOGWRN(snode->module->ctx, "Mandatory choice \"%s\" data do not exist.", snode->name);
986 } else {
987 LOGWRN(snode->module->ctx, "Mandatory node \"%s\" instance does not exist.", snode->name);
988 }
Michal Vasko7a266772024-01-23 11:02:38 +0100989 LOG_LOCBACK(parent ? 0 : 1, parent ? 1 : 0);
Michal Vasko538b8952021-02-17 11:27:26 +0100990 } else {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100991 /* node instance not found */
Michal Vasko7a266772024-01-23 11:02:38 +0100992 LOG_LOCSET(parent ? NULL : snode, parent);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100993 if (snode->nodetype == LYS_CHOICE) {
994 LOGVAL_APPTAG(snode->module->ctx, "missing-choice", LY_VCODE_NOMAND_CHOIC, snode->name);
995 } else {
996 LOGVAL(snode->module->ctx, LY_VCODE_NOMAND, snode->name);
997 }
Michal Vasko7a266772024-01-23 11:02:38 +0100998 LOG_LOCBACK(parent ? 0 : 1, parent ? 1 : 0);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +0100999 return LY_EVALID;
Michal Vasko538b8952021-02-17 11:27:26 +01001000 }
Michal Vaskobd4db892020-11-23 16:58:20 +01001001 }
1002
1003 return LY_SUCCESS;
Michal Vaskoa3881362020-01-21 15:57:35 +01001004}
1005
Michal Vaskobb844672020-07-03 11:06:12 +02001006/**
1007 * @brief Validate min/max-elements constraints, if any.
1008 *
1009 * @param[in] first First sibling to search in.
Michal Vaskobd4db892020-11-23 16:58:20 +01001010 * @param[in] parent Data parent.
Michal Vaskobb844672020-07-03 11:06:12 +02001011 * @param[in] snode Schema node to validate.
1012 * @param[in] min Minimum number of elements, 0 for no restriction.
1013 * @param[in] max Max number of elements, 0 for no restriction.
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001014 * @param[in] val_opts Validation options.
Michal Vaskobb844672020-07-03 11:06:12 +02001015 * @return LY_ERR value.
1016 */
Michal Vaskoa3881362020-01-21 15:57:35 +01001017static LY_ERR
Michal Vaskobd4db892020-11-23 16:58:20 +01001018lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001019 uint32_t min, uint32_t max, uint32_t val_opts)
Michal Vaskoa3881362020-01-21 15:57:35 +01001020{
Michal Vaskoacd83e72020-02-04 14:12:01 +01001021 uint32_t count = 0;
Michal Vasko4c583e82020-07-17 12:16:14 +02001022 struct lyd_node *iter;
Michal Vaskobd4db892020-11-23 16:58:20 +01001023 const struct lysc_when *disabled;
Michal Vaskoacd83e72020-02-04 14:12:01 +01001024
Michal Vasko9b368d32020-02-14 13:53:31 +01001025 assert(min || max);
1026
Michal Vasko4c583e82020-07-17 12:16:14 +02001027 LYD_LIST_FOR_INST(first, snode, iter) {
1028 ++count;
Michal Vasko9b368d32020-02-14 13:53:31 +01001029
Michal Vasko4c583e82020-07-17 12:16:14 +02001030 if (min && (count == min)) {
1031 /* satisfied */
1032 min = 0;
1033 if (!max) {
1034 /* nothing more to check */
Michal Vasko9b368d32020-02-14 13:53:31 +01001035 break;
1036 }
Michal Vaskoacd83e72020-02-04 14:12:01 +01001037 }
Michal Vasko4c583e82020-07-17 12:16:14 +02001038 if (max && (count > max)) {
1039 /* not satisifed */
1040 break;
1041 }
Michal Vaskoacd83e72020-02-04 14:12:01 +01001042 }
1043
Michal Vasko9b368d32020-02-14 13:53:31 +01001044 if (min) {
1045 assert(count < min);
Michal Vaskobd4db892020-11-23 16:58:20 +01001046
1047 disabled = NULL;
1048 if (lysc_has_when(snode)) {
1049 /* if there are any when conditions, they must be true for a validation error */
1050 LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, &disabled));
1051 }
1052
Michal Vasko6727c682023-02-17 10:40:26 +01001053 if (disabled) {
1054 /* satisfied */
1055 min = 0;
Michal Vaskobd4db892020-11-23 16:58:20 +01001056 }
Michal Vasko6727c682023-02-17 10:40:26 +01001057 }
1058 if (max && (count <= max)) {
1059 /* satisfied */
1060 max = 0;
Michal Vaskoacd83e72020-02-04 14:12:01 +01001061 }
1062
Michal Vasko6727c682023-02-17 10:40:26 +01001063 if (min) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001064 if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1065 /* only a warning */
Michal Vasko7a266772024-01-23 11:02:38 +01001066 LOG_LOCSET(snode, NULL);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001067 LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001068 LOG_LOCBACK(1, 0);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001069 } else {
Michal Vasko7a266772024-01-23 11:02:38 +01001070 LOG_LOCSET(snode, NULL);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001071 LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001072 LOG_LOCBACK(1, 0);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001073 return LY_EVALID;
1074 }
Michal Vasko6727c682023-02-17 10:40:26 +01001075 } else if (max) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001076 if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1077 /* only a warning */
Michal Vasko7a266772024-01-23 11:02:38 +01001078 LOG_LOCSET(NULL, iter);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001079 LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001080 LOG_LOCBACK(0, 1);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001081 } else {
Michal Vasko7a266772024-01-23 11:02:38 +01001082 LOG_LOCSET(NULL, iter);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001083 LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001084 LOG_LOCBACK(0, 1);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001085 return LY_EVALID;
1086 }
Michal Vasko6727c682023-02-17 10:40:26 +01001087 }
Michal Vaskoa3881362020-01-21 15:57:35 +01001088 return LY_SUCCESS;
1089}
1090
Michal Vaskobb844672020-07-03 11:06:12 +02001091/**
1092 * @brief Find node referenced by a list unique statement.
1093 *
1094 * @param[in] uniq_leaf Unique leaf to find.
1095 * @param[in] list List instance to use for the search.
1096 * @return Found leaf,
1097 * @return NULL if no leaf found.
1098 */
Michal Vasko14654712020-02-06 08:35:21 +01001099static struct lyd_node *
Michal Vaskobb844672020-07-03 11:06:12 +02001100lyd_val_uniq_find_leaf(const struct lysc_node_leaf *uniq_leaf, const struct lyd_node *list)
Michal Vasko14654712020-02-06 08:35:21 +01001101{
Michal Vasko9b368d32020-02-14 13:53:31 +01001102 struct lyd_node *node;
1103 const struct lysc_node *iter;
1104 size_t depth = 0, i;
Michal Vasko14654712020-02-06 08:35:21 +01001105
Michal Vasko9b368d32020-02-14 13:53:31 +01001106 /* get leaf depth */
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001107 for (iter = &uniq_leaf->node; iter && (iter != list->schema); iter = lysc_data_parent(iter)) {
Michal Vasko62ed12d2020-05-21 10:08:25 +02001108 ++depth;
Michal Vasko14654712020-02-06 08:35:21 +01001109 }
Michal Vasko9b368d32020-02-14 13:53:31 +01001110
Michal Vaskobb844672020-07-03 11:06:12 +02001111 node = (struct lyd_node *)list;
Michal Vasko9b368d32020-02-14 13:53:31 +01001112 while (node && depth) {
1113 /* find schema node with this depth */
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001114 for (i = depth - 1, iter = &uniq_leaf->node; i; iter = lysc_data_parent(iter)) {
Michal Vasko62ed12d2020-05-21 10:08:25 +02001115 --i;
Michal Vasko9b368d32020-02-14 13:53:31 +01001116 }
1117
1118 /* find iter instance in children */
1119 assert(iter->nodetype & (LYS_CONTAINER | LYS_LEAF));
Radek Krejcia1c1e542020-09-29 16:06:52 +02001120 lyd_find_sibling_val(lyd_child(node), iter, NULL, 0, &node);
Michal Vasko9b368d32020-02-14 13:53:31 +01001121 --depth;
1122 }
1123
Michal Vasko14654712020-02-06 08:35:21 +01001124 return node;
1125}
1126
Michal Vaskobb844672020-07-03 11:06:12 +02001127/**
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001128 * @brief Unique list validation callback argument.
1129 */
1130struct lyd_val_uniq_arg {
1131 LY_ARRAY_COUNT_TYPE action; /**< Action to perform - 0 to compare all uniques, n to compare only n-th unique. */
1132 uint32_t val_opts; /**< Validation options. */
1133};
1134
1135/**
Michal Vaskobb844672020-07-03 11:06:12 +02001136 * @brief Callback for comparing 2 list unique leaf values.
1137 *
Michal Vasko62524a92021-02-26 10:08:50 +01001138 * Implementation of ::lyht_value_equal_cb.
Michal Vasko14654712020-02-06 08:35:21 +01001139 */
Radek Krejci857189e2020-09-01 13:26:36 +02001140static ly_bool
1141lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *cb_data)
Michal Vasko14654712020-02-06 08:35:21 +01001142{
1143 struct ly_ctx *ctx;
1144 struct lysc_node_list *slist;
1145 struct lyd_node *diter, *first, *second;
1146 struct lyd_value *val1, *val2;
1147 char *path1, *path2, *uniq_str, *ptr;
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001148 LY_ARRAY_COUNT_TYPE u, v;
1149 struct lyd_val_uniq_arg *arg = cb_data;
1150 const uint32_t uniq_err_msg_size = 1024;
Michal Vasko14654712020-02-06 08:35:21 +01001151
1152 assert(val1_p && val2_p);
1153
1154 first = *((struct lyd_node **)val1_p);
1155 second = *((struct lyd_node **)val2_p);
Michal Vasko14654712020-02-06 08:35:21 +01001156
1157 assert(first && (first->schema->nodetype == LYS_LIST));
1158 assert(second && (second->schema == first->schema));
1159
1160 ctx = first->schema->module->ctx;
1161
1162 slist = (struct lysc_node_list *)first->schema;
1163
1164 /* compare unique leaves */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001165 if (arg->action > 0) {
1166 u = arg->action - 1;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001167 if (u < LY_ARRAY_COUNT(slist->uniques)) {
Michal Vasko14654712020-02-06 08:35:21 +01001168 goto uniquecheck;
1169 }
1170 }
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001171 LY_ARRAY_FOR(slist->uniques, u) {
Michal Vasko14654712020-02-06 08:35:21 +01001172uniquecheck:
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001173 LY_ARRAY_FOR(slist->uniques[u], v) {
Michal Vasko14654712020-02-06 08:35:21 +01001174 /* first */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001175 diter = lyd_val_uniq_find_leaf(slist->uniques[u][v], first);
Michal Vasko14654712020-02-06 08:35:21 +01001176 if (diter) {
1177 val1 = &((struct lyd_node_term *)diter)->value;
1178 } else {
1179 /* use default value */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001180 val1 = slist->uniques[u][v]->dflt;
Michal Vasko14654712020-02-06 08:35:21 +01001181 }
1182
1183 /* second */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001184 diter = lyd_val_uniq_find_leaf(slist->uniques[u][v], second);
Michal Vasko14654712020-02-06 08:35:21 +01001185 if (diter) {
1186 val2 = &((struct lyd_node_term *)diter)->value;
1187 } else {
1188 /* use default value */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001189 val2 = slist->uniques[u][v]->dflt;
Michal Vasko14654712020-02-06 08:35:21 +01001190 }
1191
aPiecek0a6705b2023-11-14 14:20:58 +01001192 if (!val1 || !val2 || val1->realtype->plugin->compare(ctx, val1, val2)) {
Michal Vasko14654712020-02-06 08:35:21 +01001193 /* values differ or either one is not set */
1194 break;
1195 }
1196 }
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001197 if (v && (v == LY_ARRAY_COUNT(slist->uniques[u]))) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001198 /* all unique leaves are the same in this set, create this nice error */
Radek Krejci635d2b82021-01-04 11:26:51 +01001199 path1 = lyd_path(first, LYD_PATH_STD, NULL, 0);
1200 path2 = lyd_path(second, LYD_PATH_STD, NULL, 0);
Michal Vasko14654712020-02-06 08:35:21 +01001201
1202 /* use buffer to rebuild the unique string */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001203 uniq_str = malloc(uniq_err_msg_size);
Michal Vasko14654712020-02-06 08:35:21 +01001204 uniq_str[0] = '\0';
1205 ptr = uniq_str;
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001206 LY_ARRAY_FOR(slist->uniques[u], v) {
1207 if (v) {
Michal Vasko14654712020-02-06 08:35:21 +01001208 strcpy(ptr, " ");
1209 ++ptr;
1210 }
Michal Vasko14ed9cd2021-01-28 14:16:25 +01001211 ptr = lysc_path_until((struct lysc_node *)slist->uniques[u][v], &slist->node, LYSC_PATH_LOG,
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001212 ptr, uniq_err_msg_size - (ptr - uniq_str));
Michal Vasko14654712020-02-06 08:35:21 +01001213 if (!ptr) {
1214 /* path will be incomplete, whatever */
1215 break;
1216 }
1217
1218 ptr += strlen(ptr);
1219 }
Michal Vasko7a266772024-01-23 11:02:38 +01001220 LOG_LOCSET(NULL, second);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001221 if (arg->val_opts & LYD_VALIDATE_OPERATIONAL) {
1222 /* only a warning */
1223 LOGWRN(ctx, "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\".", uniq_str, path1, path2);
1224 } else {
1225 LOGVAL_APPTAG(ctx, "data-not-unique", LY_VCODE_NOUNIQ, uniq_str, path1, path2);
1226 }
Michal Vasko7a266772024-01-23 11:02:38 +01001227 LOG_LOCBACK(0, 1);
Michal Vasko14654712020-02-06 08:35:21 +01001228
1229 free(path1);
1230 free(path2);
1231 free(uniq_str);
Radek Krejcif13b87b2020-12-01 22:02:17 +01001232
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001233 if (!(arg->val_opts & LYD_VALIDATE_OPERATIONAL)) {
1234 return 1;
1235 }
Michal Vasko14654712020-02-06 08:35:21 +01001236 }
1237
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001238 if (arg->action > 0) {
Michal Vasko14654712020-02-06 08:35:21 +01001239 /* done */
1240 return 0;
1241 }
1242 }
1243
1244 return 0;
1245}
1246
Michal Vaskobb844672020-07-03 11:06:12 +02001247/**
1248 * @brief Validate list unique leaves.
1249 *
1250 * @param[in] first First sibling to search in.
1251 * @param[in] snode Schema node to validate.
1252 * @param[in] uniques List unique arrays to validate.
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001253 * @param[in] val_opts Validation options.
Michal Vaskobb844672020-07-03 11:06:12 +02001254 * @return LY_ERR value.
1255 */
Michal Vaskoa3881362020-01-21 15:57:35 +01001256static LY_ERR
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001257lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode, const struct lysc_node_leaf ***uniques,
1258 uint32_t val_opts)
Michal Vaskoa3881362020-01-21 15:57:35 +01001259{
Michal Vaskob1b5c262020-03-05 14:29:47 +01001260 const struct lyd_node *diter;
Michal Vasko14654712020-02-06 08:35:21 +01001261 struct ly_set *set;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001262 LY_ARRAY_COUNT_TYPE u, v, x = 0;
Michal Vasko14654712020-02-06 08:35:21 +01001263 LY_ERR ret = LY_SUCCESS;
Michal Vasko626196f2022-08-05 12:49:52 +02001264 uint32_t hash, i;
Radek Krejci813c02d2021-04-26 10:29:19 +02001265 size_t key_len;
1266 ly_bool dyn;
1267 const void *hash_key;
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001268 struct lyd_val_uniq_arg arg, *args = NULL;
Michal Vasko8efac242023-03-30 08:24:56 +02001269 struct ly_ht **uniqtables = NULL;
Michal Vasko14654712020-02-06 08:35:21 +01001270 struct lyd_value *val;
1271 struct ly_ctx *ctx = snode->module->ctx;
1272
1273 assert(uniques);
1274
1275 /* get all list instances */
Radek Krejciba03a5a2020-08-27 14:40:41 +02001276 LY_CHECK_RET(ly_set_new(&set));
Michal Vaskob1b5c262020-03-05 14:29:47 +01001277 LY_LIST_FOR(first, diter) {
Michal Vasko9b368d32020-02-14 13:53:31 +01001278 if (diter->schema == snode) {
Radek Krejci3d92e442020-10-12 12:48:13 +02001279 ret = ly_set_add(set, (void *)diter, 1, NULL);
Michal Vaskob0099a92020-08-31 14:55:23 +02001280 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko9b368d32020-02-14 13:53:31 +01001281 }
1282 }
Michal Vasko14654712020-02-06 08:35:21 +01001283
1284 if (set->count == 2) {
1285 /* simple comparison */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001286 arg.action = 0;
1287 arg.val_opts = val_opts;
1288 if (lyd_val_uniq_list_equal(&set->objs[0], &set->objs[1], 0, &arg)) {
Michal Vasko14654712020-02-06 08:35:21 +01001289 /* instance duplication */
1290 ret = LY_EVALID;
1291 goto cleanup;
1292 }
1293 } else if (set->count > 2) {
1294 /* use hashes for comparison */
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001295 uniqtables = malloc(LY_ARRAY_COUNT(uniques) * sizeof *uniqtables);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001296 args = malloc(LY_ARRAY_COUNT(uniques) * sizeof *args);
1297 LY_CHECK_ERR_GOTO(!uniqtables || !args, LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001298 x = LY_ARRAY_COUNT(uniques);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001299 for (v = 0; v < x; v++) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001300 args[v].action = v + 1;
1301 args[v].val_opts = val_opts;
Michal Vasko626196f2022-08-05 12:49:52 +02001302 uniqtables[v] = lyht_new(lyht_get_fixed_size(set->count), sizeof(struct lyd_node *),
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001303 lyd_val_uniq_list_equal, &args[v], 0);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001304 LY_CHECK_ERR_GOTO(!uniqtables[v], LOGMEM(ctx); ret = LY_EMEM, cleanup);
Michal Vasko14654712020-02-06 08:35:21 +01001305 }
1306
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001307 for (i = 0; i < set->count; i++) {
Michal Vasko14654712020-02-06 08:35:21 +01001308 /* loop for unique - get the hash for the instances */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001309 for (u = 0; u < x; u++) {
Michal Vasko14654712020-02-06 08:35:21 +01001310 val = NULL;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001311 for (v = hash = 0; v < LY_ARRAY_COUNT(uniques[u]); v++) {
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001312 diter = lyd_val_uniq_find_leaf(uniques[u][v], set->objs[i]);
Michal Vasko14654712020-02-06 08:35:21 +01001313 if (diter) {
1314 val = &((struct lyd_node_term *)diter)->value;
1315 } else {
1316 /* use default value */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001317 val = uniques[u][v]->dflt;
Michal Vasko14654712020-02-06 08:35:21 +01001318 }
1319 if (!val) {
1320 /* unique item not present nor has default value */
1321 break;
1322 }
1323
Radek Krejci813c02d2021-04-26 10:29:19 +02001324 /* get hash key */
Michal Vaskodcfac2c2021-05-10 11:36:37 +02001325 hash_key = val->realtype->plugin->print(NULL, val, LY_VALUE_LYB, NULL, &dyn, &key_len);
Michal Vaskoae130f52023-04-20 14:25:16 +02001326 hash = lyht_hash_multi(hash, hash_key, key_len);
Radek Krejci813c02d2021-04-26 10:29:19 +02001327 if (dyn) {
1328 free((void *)hash_key);
Michal Vasko14654712020-02-06 08:35:21 +01001329 }
1330 }
1331 if (!val) {
1332 /* skip this list instance since its unique set is incomplete */
1333 continue;
1334 }
1335
1336 /* finish the hash value */
Michal Vaskoae130f52023-04-20 14:25:16 +02001337 hash = lyht_hash_multi(hash, NULL, 0);
Michal Vasko14654712020-02-06 08:35:21 +01001338
1339 /* insert into the hashtable */
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001340 ret = lyht_insert(uniqtables[u], &set->objs[i], hash, NULL);
Michal Vasko14654712020-02-06 08:35:21 +01001341 if (ret == LY_EEXIST) {
1342 /* instance duplication */
1343 ret = LY_EVALID;
1344 }
1345 LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
1346 }
1347 }
1348 }
1349
1350cleanup:
1351 ly_set_free(set, NULL);
Radek Krejci7eb54ba2020-05-18 16:30:04 +02001352 for (v = 0; v < x; v++) {
1353 if (!uniqtables[v]) {
Michal Vasko14654712020-02-06 08:35:21 +01001354 /* failed when allocating uniquetables[j], following j are not allocated */
1355 break;
1356 }
Michal Vasko77b7f90a2023-01-31 15:42:41 +01001357 lyht_free(uniqtables[v], NULL);
Michal Vasko14654712020-02-06 08:35:21 +01001358 }
1359 free(uniqtables);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001360 free(args);
Michal Vasko14654712020-02-06 08:35:21 +01001361
1362 return ret;
Michal Vaskoa3881362020-01-21 15:57:35 +01001363}
1364
Michal Vaskobb844672020-07-03 11:06:12 +02001365/**
1366 * @brief Validate data siblings based on generic schema node restrictions, recursively for schema-only nodes.
1367 *
1368 * @param[in] first First sibling to search in.
Michal Vaskobd4db892020-11-23 16:58:20 +01001369 * @param[in] parent Data parent.
Michal Vaskobb844672020-07-03 11:06:12 +02001370 * @param[in] sparent Schema parent of the nodes to check.
1371 * @param[in] mod Module of the nodes to check.
1372 * @param[in] val_opts Validation options, see @ref datavalidationoptions.
Michal Vaskoe0665742021-02-11 11:08:44 +01001373 * @param[in] int_opts Internal parser options.
Michal Vaskobb844672020-07-03 11:06:12 +02001374 * @return LY_ERR value.
1375 */
Michal Vaskoa3881362020-01-21 15:57:35 +01001376static LY_ERR
Michal Vaskobd4db892020-11-23 16:58:20 +01001377lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_node *parent,
Michal Vaskoe0665742021-02-11 11:08:44 +01001378 const struct lysc_node *sparent, const struct lysc_module *mod, uint32_t val_opts, uint32_t int_opts)
Michal Vaskocde73ac2019-11-14 16:10:27 +01001379{
Michal Vaskod027f382023-02-10 09:13:25 +01001380 LY_ERR r, rc = LY_SUCCESS;
Michal Vasko6c16cda2021-02-04 11:05:52 +01001381 const struct lysc_node *snode = NULL, *scase;
Michal Vaskoa3881362020-01-21 15:57:35 +01001382 struct lysc_node_list *slist;
Michal Vaskod8958df2020-08-05 13:27:36 +02001383 struct lysc_node_leaflist *sllist;
Radek Krejci1deb5be2020-08-26 16:43:36 +02001384 uint32_t getnext_opts;
Michal Vaskocb7526d2020-03-30 15:08:26 +02001385
Michal Vaskoe0665742021-02-11 11:08:44 +01001386 getnext_opts = LYS_GETNEXT_WITHCHOICE | (int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0);
Michal Vaskocde73ac2019-11-14 16:10:27 +01001387
Michal Vaskoa3881362020-01-21 15:57:35 +01001388 /* disabled nodes are skipped by lys_getnext */
Michal Vaskocb7526d2020-03-30 15:08:26 +02001389 while ((snode = lys_getnext(snode, sparent, mod, getnext_opts))) {
Radek Krejci7931b192020-06-25 17:05:03 +02001390 if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
Michal Vaskoe75ecfd2020-03-06 14:12:28 +01001391 continue;
1392 }
1393
Michal Vaskoa3881362020-01-21 15:57:35 +01001394 /* check min-elements and max-elements */
Michal Vaskod8958df2020-08-05 13:27:36 +02001395 if (snode->nodetype == LYS_LIST) {
Michal Vaskoa3881362020-01-21 15:57:35 +01001396 slist = (struct lysc_node_list *)snode;
1397 if (slist->min || slist->max) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001398 r = lyd_validate_minmax(first, parent, snode, slist->min, slist->max, val_opts);
Michal Vasko6727c682023-02-17 10:40:26 +01001399 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoa3881362020-01-21 15:57:35 +01001400 }
Michal Vaskod8958df2020-08-05 13:27:36 +02001401 } else if (snode->nodetype == LYS_LEAFLIST) {
1402 sllist = (struct lysc_node_leaflist *)snode;
1403 if (sllist->min || sllist->max) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001404 r = lyd_validate_minmax(first, parent, snode, sllist->min, sllist->max, val_opts);
Michal Vasko6727c682023-02-17 10:40:26 +01001405 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskod8958df2020-08-05 13:27:36 +02001406 }
Michal Vaskoacd83e72020-02-04 14:12:01 +01001407
Michal Vaskoacd83e72020-02-04 14:12:01 +01001408 } else if (snode->flags & LYS_MAND_TRUE) {
Radek Krejcif6a11002020-08-21 13:29:07 +02001409 /* check generic mandatory existence */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001410 r = lyd_validate_mandatory(first, parent, snode, val_opts);
Michal Vasko6727c682023-02-17 10:40:26 +01001411 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoa3881362020-01-21 15:57:35 +01001412 }
1413
1414 /* check unique */
1415 if (snode->nodetype == LYS_LIST) {
1416 slist = (struct lysc_node_list *)snode;
1417 if (slist->uniques) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001418 r = lyd_validate_unique(first, snode, (const struct lysc_node_leaf ***)slist->uniques, val_opts);
Michal Vasko6727c682023-02-17 10:40:26 +01001419 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoa3881362020-01-21 15:57:35 +01001420 }
1421 }
1422
Michal Vasko6c16cda2021-02-04 11:05:52 +01001423 if (snode->nodetype == LYS_CHOICE) {
1424 /* find the existing case, if any */
1425 LY_LIST_FOR(lysc_node_child(snode), scase) {
1426 if (lys_getnext_data(NULL, first, NULL, scase, NULL)) {
1427 /* validate only this case */
Michal Vaskod027f382023-02-10 09:13:25 +01001428 r = lyd_validate_siblings_schema_r(first, parent, scase, mod, val_opts, int_opts);
Michal Vasko6727c682023-02-17 10:40:26 +01001429 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko6c16cda2021-02-04 11:05:52 +01001430 break;
1431 }
1432 }
Michal Vaskoacd83e72020-02-04 14:12:01 +01001433 }
Michal Vaskocde73ac2019-11-14 16:10:27 +01001434 }
1435
Michal Vasko6727c682023-02-17 10:40:26 +01001436cleanup:
Michal Vaskod027f382023-02-10 09:13:25 +01001437 return rc;
Michal Vaskoacd83e72020-02-04 14:12:01 +01001438}
1439
Michal Vaskobb844672020-07-03 11:06:12 +02001440/**
1441 * @brief Validate obsolete nodes, only warnings are printed.
1442 *
1443 * @param[in] node Node to check.
1444 */
Michal Vaskoe75ecfd2020-03-06 14:12:28 +01001445static void
1446lyd_validate_obsolete(const struct lyd_node *node)
1447{
1448 const struct lysc_node *snode;
1449
1450 snode = node->schema;
1451 do {
1452 if (snode->flags & LYS_STATUS_OBSLT) {
Michal Vasko7a266772024-01-23 11:02:38 +01001453 LOG_LOCSET(NULL, node);
Michal Vaskoe75ecfd2020-03-06 14:12:28 +01001454 LOGWRN(snode->module->ctx, "Obsolete schema node \"%s\" instantiated in data.", snode->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001455 LOG_LOCBACK(0, 1);
Michal Vaskoe75ecfd2020-03-06 14:12:28 +01001456 break;
1457 }
1458
1459 snode = snode->parent;
1460 } while (snode && (snode->nodetype & (LYS_CHOICE | LYS_CASE)));
1461}
1462
Michal Vaskobb844672020-07-03 11:06:12 +02001463/**
1464 * @brief Validate must conditions of a data node.
1465 *
1466 * @param[in] node Node to validate.
Michal Vaskod027f382023-02-10 09:13:25 +01001467 * @param[in] val_opts Validation options.
Michal Vaskoe0665742021-02-11 11:08:44 +01001468 * @param[in] int_opts Internal parser options.
Michal Vasko906bafa2022-04-22 12:28:55 +02001469 * @param[in] xpath_options Additional XPath options to use.
Michal Vaskobb844672020-07-03 11:06:12 +02001470 * @return LY_ERR value.
1471 */
Michal Vaskocc048b22020-03-27 15:52:38 +01001472static LY_ERR
Michal Vaskod027f382023-02-10 09:13:25 +01001473lyd_validate_must(const struct lyd_node *node, uint32_t val_opts, uint32_t int_opts, uint32_t xpath_options)
Michal Vaskocc048b22020-03-27 15:52:38 +01001474{
Michal Vaskod027f382023-02-10 09:13:25 +01001475 LY_ERR r, rc = LY_SUCCESS;
Michal Vaskocc048b22020-03-27 15:52:38 +01001476 struct lyxp_set xp_set;
1477 struct lysc_must *musts;
1478 const struct lyd_node *tree;
Radek Krejci9a3823e2021-01-27 20:26:46 +01001479 const struct lysc_node *schema;
Michal Vaskoe9391c72021-10-05 10:04:56 +02001480 const char *emsg, *eapptag;
Michal Vaskofd69e1d2020-07-03 11:57:17 +02001481 LY_ARRAY_COUNT_TYPE u;
Michal Vaskocc048b22020-03-27 15:52:38 +01001482
Michal Vaskoe0665742021-02-11 11:08:44 +01001483 assert((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) != (LYD_INTOPT_RPC | LYD_INTOPT_REPLY));
1484 assert((int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) != (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY));
1485
Radek Krejci9a3823e2021-01-27 20:26:46 +01001486 if (node->schema->nodetype & (LYS_ACTION | LYS_RPC)) {
Michal Vaskoe0665742021-02-11 11:08:44 +01001487 if (int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION)) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001488 schema = &((struct lysc_node_action *)node->schema)->input.node;
Michal Vaskoe0665742021-02-11 11:08:44 +01001489 } else if (int_opts & LYD_INTOPT_REPLY) {
Radek Krejci9a3823e2021-01-27 20:26:46 +01001490 schema = &((struct lysc_node_action *)node->schema)->output.node;
Michal Vaskocb7526d2020-03-30 15:08:26 +02001491 } else {
Michal Vaskoa1db2342021-07-19 12:23:23 +02001492 LOGINT_RET(LYD_CTX(node));
Michal Vaskocb7526d2020-03-30 15:08:26 +02001493 }
Radek Krejci9a3823e2021-01-27 20:26:46 +01001494 } else {
1495 schema = node->schema;
Michal Vaskocc048b22020-03-27 15:52:38 +01001496 }
Radek Krejci9a3823e2021-01-27 20:26:46 +01001497 musts = lysc_node_musts(schema);
Michal Vaskocc048b22020-03-27 15:52:38 +01001498 if (!musts) {
1499 /* no must to evaluate */
1500 return LY_SUCCESS;
1501 }
1502
1503 /* find first top-level node */
Michal Vasko9e685082021-01-29 14:49:09 +01001504 for (tree = node; tree->parent; tree = lyd_parent(tree)) {}
Michal Vaskof9221e62021-02-04 12:10:14 +01001505 tree = lyd_first_sibling(tree);
Michal Vaskocc048b22020-03-27 15:52:38 +01001506
1507 LY_ARRAY_FOR(musts, u) {
1508 memset(&xp_set, 0, sizeof xp_set);
1509
1510 /* evaluate must */
Michal Vaskod027f382023-02-10 09:13:25 +01001511 r = lyxp_eval(LYD_CTX(node), musts[u].cond, node->schema->module, LY_VALUE_SCHEMA_RESOLVED,
Michal Vaskoa3e92bc2022-07-29 14:56:23 +02001512 musts[u].prefixes, node, node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_options);
Michal Vaskod027f382023-02-10 09:13:25 +01001513 if (r == LY_EINCOMPLETE) {
Michal Vasko2deae4c2023-11-08 11:36:59 +01001514 LOGERR(LYD_CTX(node), LY_EINCOMPLETE,
1515 "Must \"%s\" depends on a node with a when condition, which has not been evaluated.", musts[u].cond->expr);
Michal Vaskoa1db2342021-07-19 12:23:23 +02001516 }
Michal Vaskod027f382023-02-10 09:13:25 +01001517 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskocc048b22020-03-27 15:52:38 +01001518
1519 /* check the result */
1520 lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
Michal Vasko004d3152020-06-11 19:59:22 +02001521 if (!xp_set.val.bln) {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001522 if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1523 /* only a warning */
1524 emsg = musts[u].emsg;
Michal Vasko7a266772024-01-23 11:02:38 +01001525 LOG_LOCSET(NULL, node);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001526 if (emsg) {
1527 LOGWRN(LYD_CTX(node), "%s", emsg);
1528 } else {
1529 LOGWRN(LYD_CTX(node), "Must condition \"%s\" not satisfied.", musts[u].cond->expr);
1530 }
Michal Vasko7a266772024-01-23 11:02:38 +01001531 LOG_LOCBACK(0, 1);
Michal Vaskoe9391c72021-10-05 10:04:56 +02001532 } else {
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001533 /* use specific error information */
1534 emsg = musts[u].emsg;
1535 eapptag = musts[u].eapptag ? musts[u].eapptag : "must-violation";
Michal Vasko7a266772024-01-23 11:02:38 +01001536 LOG_LOCSET(NULL, node);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001537 if (emsg) {
1538 LOGVAL_APPTAG(LYD_CTX(node), eapptag, LYVE_DATA, "%s", emsg);
1539 } else {
1540 LOGVAL_APPTAG(LYD_CTX(node), eapptag, LY_VCODE_NOMUST, musts[u].cond->expr);
1541 }
Michal Vasko7a266772024-01-23 11:02:38 +01001542 LOG_LOCBACK(0, 1);
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001543 r = LY_EVALID;
1544 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoe9391c72021-10-05 10:04:56 +02001545 }
Michal Vaskocc048b22020-03-27 15:52:38 +01001546 }
1547 }
1548
Michal Vaskod027f382023-02-10 09:13:25 +01001549cleanup:
1550 return rc;
Michal Vaskocc048b22020-03-27 15:52:38 +01001551}
1552
Michal Vaskoe0665742021-02-11 11:08:44 +01001553/**
1554 * @brief Perform all remaining validation tasks, the data tree must be final when calling this function.
1555 *
1556 * @param[in] first First sibling.
1557 * @param[in] parent Data parent.
1558 * @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
1559 * @param[in] mod Module of the siblings, NULL for nested siblings.
1560 * @param[in] val_opts Validation options (@ref datavalidationoptions).
1561 * @param[in] int_opts Internal parser options.
Michal Vasko906bafa2022-04-22 12:28:55 +02001562 * @param[in] must_xp_opts Additional XPath options to use for evaluating "must".
Michal Vaskoe0665742021-02-11 11:08:44 +01001563 * @return LY_ERR value.
1564 */
1565static LY_ERR
Michal Vaskobd4db892020-11-23 16:58:20 +01001566lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *sparent,
Michal Vasko906bafa2022-04-22 12:28:55 +02001567 const struct lys_module *mod, uint32_t val_opts, uint32_t int_opts, uint32_t must_xp_opts)
Michal Vaskoacd83e72020-02-04 14:12:01 +01001568{
Michal Vaskod027f382023-02-10 09:13:25 +01001569 LY_ERR r, rc = LY_SUCCESS;
Michal Vasko22e8f1f2021-12-02 09:26:06 +01001570 const char *innode;
Michal Vaskob8093b92023-12-21 13:23:07 +01001571 struct lyd_node *node;
Michal Vaskoacd83e72020-02-04 14:12:01 +01001572
Michal Vasko14654712020-02-06 08:35:21 +01001573 /* validate all restrictions of nodes themselves */
Michal Vaskob8093b92023-12-21 13:23:07 +01001574 LY_LIST_FOR(first, node) {
Michal Vasko61ad1ff2022-02-10 15:48:39 +01001575 if (node->flags & LYD_EXT) {
1576 /* ext instance data should have already been validated */
1577 continue;
1578 }
1579
Michal Vaskoa8c61722020-03-27 16:59:32 +01001580 /* opaque data */
1581 if (!node->schema) {
Michal Vaskoac6f4be2022-05-02 10:16:50 +02001582 r = lyd_parse_opaq_error(node);
Michal Vaskod027f382023-02-10 09:13:25 +01001583 goto next_iter;
Michal Vaskoa8c61722020-03-27 16:59:32 +01001584 }
1585
Michal Vasko6344e7a2022-05-10 10:08:53 +02001586 if (!node->parent && mod && (lyd_owner_module(node) != mod)) {
1587 /* all top-level data from this module checked */
Michal Vasko6344e7a2022-05-10 10:08:53 +02001588 break;
1589 }
1590
Michal Vasko8d289f92021-12-02 10:11:00 +01001591 /* no state/input/output/op data */
Michal Vasko22e8f1f2021-12-02 09:26:06 +01001592 innode = NULL;
Radek Krejci7931b192020-06-25 17:05:03 +02001593 if ((val_opts & LYD_VALIDATE_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001594 innode = "state";
Michal Vaskoe0665742021-02-11 11:08:44 +01001595 } else if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION)) && (node->schema->flags & LYS_IS_OUTPUT)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001596 innode = "output";
Michal Vaskoe0665742021-02-11 11:08:44 +01001597 } else if ((int_opts & LYD_INTOPT_REPLY) && (node->schema->flags & LYS_IS_INPUT)) {
Radek Krejci2efc45b2020-12-22 16:25:44 +01001598 innode = "input";
Michal Vasko8d289f92021-12-02 10:11:00 +01001599 } else if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_RPC)) {
1600 innode = "rpc";
1601 } else if (!(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_ACTION)) {
1602 innode = "action";
1603 } else if (!(int_opts & LYD_INTOPT_NOTIF) && (node->schema->nodetype == LYS_NOTIF)) {
1604 innode = "notification";
Michal Vasko22e8f1f2021-12-02 09:26:06 +01001605 }
1606 if (innode) {
Michal Vasko7a266772024-01-23 11:02:38 +01001607 LOG_LOCSET(NULL, node);
Michal Vasko22e8f1f2021-12-02 09:26:06 +01001608 LOGVAL(LYD_CTX(node), LY_VCODE_UNEXPNODE, innode, node->schema->name);
Michal Vasko7a266772024-01-23 11:02:38 +01001609 LOG_LOCBACK(0, 1);
Michal Vaskod027f382023-02-10 09:13:25 +01001610 r = LY_EVALID;
1611 goto next_iter;
Michal Vasko5b37a352020-03-06 13:38:33 +01001612 }
1613
Michal Vaskoe75ecfd2020-03-06 14:12:28 +01001614 /* obsolete data */
1615 lyd_validate_obsolete(node);
1616
Michal Vaskocc048b22020-03-27 15:52:38 +01001617 /* node's musts */
Michal Vaskod027f382023-02-10 09:13:25 +01001618 if ((r = lyd_validate_must(node, val_opts, int_opts, must_xp_opts))) {
1619 goto next_iter;
Michal Vasko22e8f1f2021-12-02 09:26:06 +01001620 }
Michal Vaskocc048b22020-03-27 15:52:38 +01001621
Michal Vasko53d97a12020-11-05 17:39:10 +01001622 /* node value was checked by plugins */
Radek Krejci2efc45b2020-12-22 16:25:44 +01001623
Michal Vaskod027f382023-02-10 09:13:25 +01001624next_iter:
Michal Vaskod027f382023-02-10 09:13:25 +01001625 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko14654712020-02-06 08:35:21 +01001626 }
Michal Vaskocde73ac2019-11-14 16:10:27 +01001627
Michal Vasko14654712020-02-06 08:35:21 +01001628 /* validate schema-based restrictions */
Michal Vaskod027f382023-02-10 09:13:25 +01001629 r = lyd_validate_siblings_schema_r(first, parent, sparent, mod ? mod->compiled : NULL, val_opts, int_opts);
1630 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vasko14654712020-02-06 08:35:21 +01001631
Michal Vaskob1b5c262020-03-05 14:29:47 +01001632 LY_LIST_FOR(first, node) {
Michal Vaskodc9e27b2023-08-21 11:56:14 +02001633 if (!node->schema || (!node->parent && mod && (lyd_owner_module(node) != mod))) {
1634 /* only opaque data following or all top-level data from this module checked */
Michal Vasko19034e22021-07-19 12:24:14 +02001635 break;
1636 }
1637
Michal Vasko14654712020-02-06 08:35:21 +01001638 /* validate all children recursively */
Michal Vaskod027f382023-02-10 09:13:25 +01001639 r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, val_opts, int_opts, must_xp_opts);
1640 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskocde73ac2019-11-14 16:10:27 +01001641
Michal Vaskob1b5c262020-03-05 14:29:47 +01001642 /* set default for containers */
Michal Vasko4754d4a2022-12-01 10:11:21 +01001643 lyd_cont_set_dflt(node);
Michal Vasko9b368d32020-02-14 13:53:31 +01001644 }
1645
Michal Vaskod027f382023-02-10 09:13:25 +01001646cleanup:
1647 return rc;
Michal Vasko9b368d32020-02-14 13:53:31 +01001648}
1649
Radek Krejci7931b192020-06-25 17:05:03 +02001650/**
Michal Vaskoddd76592022-01-17 13:34:48 +01001651 * @brief Validate extension instance data by storing it in its unres set.
1652 *
1653 * @param[in] sibling First sibling with ::LYD_EXT flag, all the following ones are expected to have it, too.
1654 * @param[in,out] ext_val Set with parsed extension instance data to validate.
1655 * @return LY_ERR value.
1656 */
1657static LY_ERR
1658lyd_validate_nested_ext(struct lyd_node *sibling, struct ly_set *ext_val)
1659{
1660 struct lyd_node *node;
1661 struct lyd_ctx_ext_val *ext_v;
1662 struct lysc_ext_instance *nested_exts, *ext = NULL;
1663 LY_ARRAY_COUNT_TYPE u;
1664
1665 /* check of basic assumptions */
1666 if (!sibling->parent || !sibling->parent->schema) {
1667 LOGINT_RET(LYD_CTX(sibling));
1668 }
1669 LY_LIST_FOR(sibling, node) {
1670 if (!(node->flags & LYD_EXT)) {
1671 LOGINT_RET(LYD_CTX(sibling));
1672 }
1673 }
1674
1675 /* try to find the extension instance */
1676 nested_exts = sibling->parent->schema->exts;
1677 LY_ARRAY_FOR(nested_exts, u) {
1678 if (nested_exts[u].def->plugin->validate) {
1679 if (ext) {
1680 /* more extension instances with validate callback */
1681 LOGINT_RET(LYD_CTX(sibling));
1682 }
1683 ext = &nested_exts[u];
1684 }
1685 }
1686 if (!ext) {
1687 /* no extension instance with validate callback */
1688 LOGINT_RET(LYD_CTX(sibling));
1689 }
1690
1691 /* store for validation */
1692 ext_v = malloc(sizeof *ext_v);
1693 LY_CHECK_ERR_RET(!ext_v, LOGMEM(LYD_CTX(sibling)), LY_EMEM);
1694 ext_v->ext = ext;
1695 ext_v->sibling = sibling;
1696 LY_CHECK_RET(ly_set_add(ext_val, ext_v, 1, NULL));
1697
1698 return LY_SUCCESS;
1699}
1700
Michal Vasko135719f2022-08-25 12:18:17 +02001701LY_ERR
1702lyd_validate_node_ext(struct lyd_node *node, struct ly_set *ext_node)
1703{
1704 struct lyd_ctx_ext_node *ext_n;
1705 struct lysc_ext_instance *exts;
1706 LY_ARRAY_COUNT_TYPE u;
1707
1708 /* try to find a relevant extension instance with node callback */
1709 exts = node->schema->exts;
1710 LY_ARRAY_FOR(exts, u) {
1711 if (exts[u].def->plugin && exts[u].def->plugin->node) {
1712 /* store for validation */
1713 ext_n = malloc(sizeof *ext_n);
1714 LY_CHECK_ERR_RET(!ext_n, LOGMEM(LYD_CTX(node)), LY_EMEM);
1715 ext_n->ext = &exts[u];
1716 ext_n->node = node;
1717 LY_CHECK_RET(ly_set_add(ext_node, ext_n, 1, NULL));
1718 }
1719 }
1720
1721 return LY_SUCCESS;
1722}
1723
Michal Vaskoddd76592022-01-17 13:34:48 +01001724/**
Michal Vaskobb844672020-07-03 11:06:12 +02001725 * @brief Validate the whole data subtree.
1726 *
1727 * @param[in] root Subtree root.
Michal Vaskoe0665742021-02-11 11:08:44 +01001728 * @param[in,out] node_when Set for nodes with when conditions.
Michal Vasko32711382020-12-03 14:14:31 +01001729 * @param[in,out] node_types Set for unres node types.
1730 * @param[in,out] meta_types Set for unres metadata types.
Michal Vasko1a6e6902022-08-26 08:35:09 +02001731 * @param[in,out] ext_node Set with nodes with extensions to validate.
Michal Vaskoddd76592022-01-17 13:34:48 +01001732 * @param[in,out] ext_val Set for parsed extension data to validate.
Michal Vaskod027f382023-02-10 09:13:25 +01001733 * @param[in] val_opts Validation options.
Michal Vasko8104fd42020-07-13 11:09:51 +02001734 * @param[in,out] diff Validation diff.
Michal Vaskobb844672020-07-03 11:06:12 +02001735 * @return LY_ERR value.
Radek Krejci7931b192020-06-25 17:05:03 +02001736 */
Michal Vaskob1b5c262020-03-05 14:29:47 +01001737static LY_ERR
Michal Vaskoddd76592022-01-17 13:34:48 +01001738lyd_validate_subtree(struct lyd_node *root, struct ly_set *node_when, struct ly_set *node_types,
Michal Vaskod027f382023-02-10 09:13:25 +01001739 struct ly_set *meta_types, struct ly_set *ext_node, struct ly_set *ext_val, uint32_t val_opts,
Michal Vasko1a6e6902022-08-26 08:35:09 +02001740 struct lyd_node **diff)
Michal Vaskofea12c62020-03-30 11:00:15 +02001741{
Michal Vaskod027f382023-02-10 09:13:25 +01001742 LY_ERR r, rc = LY_SUCCESS;
Michal Vaskofea12c62020-03-30 11:00:15 +02001743 const struct lyd_meta *meta;
Michal Vasko193dacd2022-10-13 08:43:05 +02001744 const struct lysc_type *type;
Michal Vasko56daf732020-08-10 10:57:18 +02001745 struct lyd_node *node;
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001746 uint32_t impl_opts;
Michal Vaskofea12c62020-03-30 11:00:15 +02001747
Michal Vasko56daf732020-08-10 10:57:18 +02001748 LYD_TREE_DFS_BEGIN(root, node) {
Michal Vaskoddd76592022-01-17 13:34:48 +01001749 if (node->flags & LYD_EXT) {
1750 /* validate using the extension instance callback */
1751 return lyd_validate_nested_ext(node, ext_val);
1752 }
1753
Michal Vasko5900da42021-08-04 11:02:43 +02001754 if (!node->schema) {
Michal Vaskoddd76592022-01-17 13:34:48 +01001755 /* do not validate opaque nodes */
aPiecek18a844e2021-08-10 11:06:24 +02001756 goto next_node;
Michal Vasko5900da42021-08-04 11:02:43 +02001757 }
1758
Michal Vasko0275cf62020-11-05 17:40:30 +01001759 LY_LIST_FOR(node->meta, meta) {
Michal Vaskofbd037c2022-11-08 10:34:20 +01001760 lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
Michal Vasko193dacd2022-10-13 08:43:05 +02001761 if (type->plugin->validate) {
Michal Vasko0275cf62020-11-05 17:40:30 +01001762 /* metadata type resolution */
Michal Vaskod027f382023-02-10 09:13:25 +01001763 r = ly_set_add(meta_types, (void *)meta, 1, NULL);
1764 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskofea12c62020-03-30 11:00:15 +02001765 }
Michal Vasko0275cf62020-11-05 17:40:30 +01001766 }
Michal Vaskofea12c62020-03-30 11:00:15 +02001767
Michal Vasko0275cf62020-11-05 17:40:30 +01001768 if ((node->schema->nodetype & LYD_NODE_TERM) && ((struct lysc_node_leaf *)node->schema)->type->plugin->validate) {
1769 /* node type resolution */
Michal Vaskod027f382023-02-10 09:13:25 +01001770 r = ly_set_add(node_types, (void *)node, 1, NULL);
1771 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vasko0275cf62020-11-05 17:40:30 +01001772 } else if (node->schema->nodetype & LYD_NODE_INNER) {
1773 /* new node validation, autodelete */
Michal Vaskod027f382023-02-10 09:13:25 +01001774 r = lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, val_opts, diff);
1775 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskofea12c62020-03-30 11:00:15 +02001776
Michal Vasko0275cf62020-11-05 17:40:30 +01001777 /* add nested defaults */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001778 impl_opts = 0;
1779 if (val_opts & LYD_VALIDATE_NO_STATE) {
1780 impl_opts |= LYD_IMPLICIT_NO_STATE;
1781 }
1782 if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
1783 impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
1784 }
1785 r = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, diff);
Michal Vaskod027f382023-02-10 09:13:25 +01001786 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vasko0275cf62020-11-05 17:40:30 +01001787 }
Michal Vaskofea12c62020-03-30 11:00:15 +02001788
Michal Vaskof4d67ea2021-03-31 13:53:21 +02001789 if (lysc_has_when(node->schema)) {
Michal Vasko0275cf62020-11-05 17:40:30 +01001790 /* when evaluation */
Michal Vaskod027f382023-02-10 09:13:25 +01001791 r = ly_set_add(node_when, (void *)node, 1, NULL);
1792 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskofea12c62020-03-30 11:00:15 +02001793 }
1794
Michal Vasko1a6e6902022-08-26 08:35:09 +02001795 /* store for ext instance node validation, if needed */
Michal Vaskod027f382023-02-10 09:13:25 +01001796 r = lyd_validate_node_ext(node, ext_node);
1797 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vasko1a6e6902022-08-26 08:35:09 +02001798
aPiecek18a844e2021-08-10 11:06:24 +02001799next_node:
Michal Vasko56daf732020-08-10 10:57:18 +02001800 LYD_TREE_DFS_END(root, node);
Michal Vaskofea12c62020-03-30 11:00:15 +02001801 }
1802
Michal Vaskod027f382023-02-10 09:13:25 +01001803cleanup:
1804 return rc;
Michal Vaskofea12c62020-03-30 11:00:15 +02001805}
1806
Michal Vaskoe0665742021-02-11 11:08:44 +01001807LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001808lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_opts,
Michal Vaskoddd76592022-01-17 13:34:48 +01001809 ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
Michal Vasko135719f2022-08-25 12:18:17 +02001810 struct ly_set *ext_node_p, struct ly_set *ext_val_p, struct lyd_node **diff)
Michal Vaskof03ed032020-03-04 13:31:44 +01001811{
Michal Vaskod027f382023-02-10 09:13:25 +01001812 LY_ERR r, rc = LY_SUCCESS;
Michal Vasko73e47212020-12-03 14:20:16 +01001813 struct lyd_node *first, *next, **first2, *iter;
Michal Vaskob1b5c262020-03-05 14:29:47 +01001814 const struct lys_module *mod;
Michal Vasko135719f2022-08-25 12:18:17 +02001815 struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_node = {0}, ext_val = {0};
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001816 uint32_t i = 0, impl_opts;
Michal Vaskof03ed032020-03-04 13:31:44 +01001817
Michal Vaskoe0665742021-02-11 11:08:44 +01001818 assert(tree && ctx);
Michal Vasko135719f2022-08-25 12:18:17 +02001819 assert((node_when_p && node_types_p && meta_types_p && ext_node_p && ext_val_p) ||
1820 (!node_when_p && !node_types_p && !meta_types_p && !ext_node_p && !ext_val_p));
Michal Vaskoe0665742021-02-11 11:08:44 +01001821
1822 if (!node_when_p) {
1823 node_when_p = &node_when;
1824 node_types_p = &node_types;
1825 meta_types_p = &meta_types;
Michal Vasko135719f2022-08-25 12:18:17 +02001826 ext_node_p = &ext_node;
Michal Vaskoddd76592022-01-17 13:34:48 +01001827 ext_val_p = &ext_val;
Michal Vasko8104fd42020-07-13 11:09:51 +02001828 }
Michal Vaskof03ed032020-03-04 13:31:44 +01001829
Michal Vaskob1b5c262020-03-05 14:29:47 +01001830 next = *tree;
1831 while (1) {
Radek Krejci7931b192020-06-25 17:05:03 +02001832 if (val_opts & LYD_VALIDATE_PRESENT) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001833 mod = lyd_data_next_module(&next, &first);
1834 } else {
Michal Vasko26e80012020-07-08 10:55:46 +02001835 mod = lyd_mod_next_module(next, module, ctx, &i, &first);
Michal Vaskof03ed032020-03-04 13:31:44 +01001836 }
Michal Vaskob1b5c262020-03-05 14:29:47 +01001837 if (!mod) {
1838 break;
1839 }
Michal Vasko7c4cf1e2020-06-22 10:04:30 +02001840 if (!first || (first == *tree)) {
Michal Vaskob1b5c262020-03-05 14:29:47 +01001841 /* make sure first2 changes are carried to tree */
1842 first2 = tree;
1843 } else {
1844 first2 = &first;
1845 }
1846
1847 /* validate new top-level nodes of this module, autodelete */
Michal Vaskoa6139e02023-10-03 14:13:22 +02001848 r = lyd_validate_new(first2, *first2 ? lysc_data_parent((*first2)->schema) : NULL, mod, val_opts, diff);
Michal Vaskod027f382023-02-10 09:13:25 +01001849 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +01001850
Radek Krejci7be7b9f2021-02-24 11:46:27 +01001851 /* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets
1852 * (lyd_validate_subtree() adds all the nodes in that case) */
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001853 impl_opts = 0;
1854 if (val_opts & LYD_VALIDATE_NO_STATE) {
1855 impl_opts |= LYD_IMPLICIT_NO_STATE;
1856 }
1857 if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
1858 impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
1859 }
Michal Vaskoa6139e02023-10-03 14:13:22 +02001860 r = lyd_new_implicit_r(lyd_parent(*first2), first2, NULL, mod, validate_subtree ? NULL : node_when_p,
Michal Vaskoaf5a8dd2023-03-02 11:25:02 +01001861 validate_subtree ? NULL : node_types_p, validate_subtree ? NULL : ext_node_p, impl_opts, diff);
Michal Vaskod027f382023-02-10 09:13:25 +01001862 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +01001863
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001864 /* our first module node pointer may no longer be the first */
Michal Vasko598063b2021-07-19 11:39:05 +02001865 first = *first2;
1866 lyd_first_module_sibling(&first, mod);
1867 if (!first || (first == *tree)) {
1868 first2 = tree;
1869 } else {
1870 first2 = &first;
Michal Vaskod3bb12f2020-12-04 14:33:09 +01001871 }
1872
Michal Vaskoe0665742021-02-11 11:08:44 +01001873 if (validate_subtree) {
1874 /* process nested nodes */
1875 LY_LIST_FOR(*first2, iter) {
Michal Vasko0e72b7a2021-07-16 14:53:27 +02001876 if (lyd_owner_module(iter) != mod) {
1877 break;
1878 }
1879
Michal Vaskod027f382023-02-10 09:13:25 +01001880 r = lyd_validate_subtree(iter, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p,
1881 val_opts, diff);
1882 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01001883 }
Michal Vaskob1b5c262020-03-05 14:29:47 +01001884 }
1885
1886 /* finish incompletely validated terminal values/attributes and when conditions */
Michal Vaskod027f382023-02-10 09:13:25 +01001887 r = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p,
Michal Vasko135719f2022-08-25 12:18:17 +02001888 ext_node_p, ext_val_p, val_opts, diff);
Michal Vaskod027f382023-02-10 09:13:25 +01001889 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
Michal Vaskob1b5c262020-03-05 14:29:47 +01001890
Michal Vasko6b14c7e2023-11-09 12:08:14 +01001891 if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) {
1892 /* perform final validation that assumes the data tree is final */
1893 r = lyd_validate_final_r(*first2, NULL, NULL, mod, val_opts, 0, 0);
1894 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1895 }
Michal Vaskof03ed032020-03-04 13:31:44 +01001896 }
1897
Michal Vaskof03ed032020-03-04 13:31:44 +01001898cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001899 ly_set_erase(&node_when, NULL);
Michal Vasko32711382020-12-03 14:14:31 +01001900 ly_set_erase(&node_types, NULL);
1901 ly_set_erase(&meta_types, NULL);
Michal Vasko135719f2022-08-25 12:18:17 +02001902 ly_set_erase(&ext_node, free);
Michal Vaskoddd76592022-01-17 13:34:48 +01001903 ly_set_erase(&ext_val, free);
Michal Vaskod027f382023-02-10 09:13:25 +01001904 return rc;
Michal Vaskof03ed032020-03-04 13:31:44 +01001905}
Michal Vaskob1b5c262020-03-05 14:29:47 +01001906
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001907LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001908lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff)
Michal Vaskob1b5c262020-03-05 14:29:47 +01001909{
Michal Vaskoe0665742021-02-11 11:08:44 +01001910 LY_CHECK_ARG_RET(NULL, tree, *tree || ctx, LY_EINVAL);
Michal Vasko892f5bf2021-11-24 10:41:05 +01001911 LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
Michal Vaskoe0665742021-02-11 11:08:44 +01001912 if (!ctx) {
1913 ctx = LYD_CTX(*tree);
1914 }
1915 if (diff) {
1916 *diff = NULL;
1917 }
1918
Michal Vasko135719f2022-08-25 12:18:17 +02001919 return lyd_validate(tree, NULL, ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL, diff);
Michal Vaskob1b5c262020-03-05 14:29:47 +01001920}
1921
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01001922LIBYANG_API_DEF LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +02001923lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff)
Michal Vaskob1b5c262020-03-05 14:29:47 +01001924{
Michal Vasko6b14c7e2023-11-09 12:08:14 +01001925 LY_CHECK_ARG_RET(NULL, tree, module, !(val_opts & LYD_VALIDATE_PRESENT), LY_EINVAL);
1926 LY_CHECK_CTX_EQUAL_RET(*tree ? LYD_CTX(*tree) : NULL, module->ctx, LY_EINVAL);
Michal Vaskoe0665742021-02-11 11:08:44 +01001927 if (diff) {
1928 *diff = NULL;
1929 }
1930
Michal Vasko6b14c7e2023-11-09 12:08:14 +01001931 return lyd_validate(tree, module, module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, NULL, diff);
1932}
1933
1934LIBYANG_API_DEF LY_ERR
1935lyd_validate_module_final(struct lyd_node *tree, const struct lys_module *module, uint32_t val_opts)
1936{
1937 LY_ERR r, rc = LY_SUCCESS;
1938 struct lyd_node *first;
1939 const struct lys_module *mod;
1940 uint32_t i = 0;
1941
1942 LY_CHECK_ARG_RET(NULL, module, !(val_opts & (LYD_VALIDATE_PRESENT | LYD_VALIDATE_NOT_FINAL)), LY_EINVAL);
Michal Vasko506fab42024-05-27 08:32:49 +02001943 LY_CHECK_CTX_EQUAL_RET(tree ? LYD_CTX(tree) : NULL, module->ctx, LY_EINVAL);
Michal Vasko6b14c7e2023-11-09 12:08:14 +01001944
1945 /* module is unchanged but we need to get the first module data node */
1946 mod = lyd_mod_next_module(tree, module, module->ctx, &i, &first);
1947 assert(mod);
1948
1949 /* perform final validation that assumes the data tree is final */
1950 r = lyd_validate_final_r(first, NULL, NULL, mod, val_opts, 0, 0);
1951 LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1952
1953cleanup:
1954 return rc;
Michal Vaskob1b5c262020-03-05 14:29:47 +01001955}
Michal Vaskofea12c62020-03-30 11:00:15 +02001956
Michal Vaskobb844672020-07-03 11:06:12 +02001957/**
1958 * @brief Find nodes for merging an operation into data tree for validation.
1959 *
1960 * @param[in] op_tree Full operation data tree.
1961 * @param[in] op_node Operation node itself.
1962 * @param[in] tree Data tree to be merged into.
1963 * @param[out] op_subtree Operation subtree to merge.
Michal Vasko2f03d222020-12-09 18:15:51 +01001964 * @param[out] tree_sibling Data tree sibling to merge next to, is set if @p tree_parent is NULL.
1965 * @param[out] tree_parent Data tree parent to merge into, is set if @p tree_sibling is NULL.
Michal Vaskobb844672020-07-03 11:06:12 +02001966 */
Michal Vaskocb7526d2020-03-30 15:08:26 +02001967static void
Michal Vaskobb844672020-07-03 11:06:12 +02001968lyd_val_op_merge_find(const struct lyd_node *op_tree, const struct lyd_node *op_node, const struct lyd_node *tree,
Michal Vasko2f03d222020-12-09 18:15:51 +01001969 struct lyd_node **op_subtree, struct lyd_node **tree_sibling, struct lyd_node **tree_parent)
Michal Vaskofea12c62020-03-30 11:00:15 +02001970{
Michal Vaskocb7526d2020-03-30 15:08:26 +02001971 const struct lyd_node *tree_iter, *op_iter;
Michal Vaskob10c93b2022-12-14 12:16:27 +01001972 struct lyd_node *match = NULL;
Michal Vaskofea12c62020-03-30 11:00:15 +02001973 uint32_t i, cur_depth, op_depth;
Michal Vaskofea12c62020-03-30 11:00:15 +02001974
Michal Vasko2f03d222020-12-09 18:15:51 +01001975 *op_subtree = NULL;
1976 *tree_sibling = NULL;
1977 *tree_parent = NULL;
1978
Michal Vaskocb7526d2020-03-30 15:08:26 +02001979 /* learn op depth (top-level being depth 0) */
Michal Vaskofea12c62020-03-30 11:00:15 +02001980 op_depth = 0;
Michal Vasko9e685082021-01-29 14:49:09 +01001981 for (op_iter = op_node; op_iter != op_tree; op_iter = lyd_parent(op_iter)) {
Michal Vaskofea12c62020-03-30 11:00:15 +02001982 ++op_depth;
1983 }
1984
1985 /* find where to merge op */
1986 tree_iter = tree;
1987 cur_depth = op_depth;
Michal Vasko2f03d222020-12-09 18:15:51 +01001988 while (cur_depth && tree_iter) {
Michal Vaskofea12c62020-03-30 11:00:15 +02001989 /* find op iter in tree */
1990 lyd_find_sibling_first(tree_iter, op_iter, &match);
1991 if (!match) {
1992 break;
1993 }
1994
1995 /* move tree_iter */
Radek Krejcia1c1e542020-09-29 16:06:52 +02001996 tree_iter = lyd_child(match);
Michal Vaskofea12c62020-03-30 11:00:15 +02001997
1998 /* move depth */
1999 --cur_depth;
Michal Vasko2f03d222020-12-09 18:15:51 +01002000
2001 /* find next op parent */
2002 op_iter = op_node;
2003 for (i = 0; i < cur_depth; ++i) {
Michal Vasko9e685082021-01-29 14:49:09 +01002004 op_iter = lyd_parent(op_iter);
Michal Vasko2f03d222020-12-09 18:15:51 +01002005 }
Michal Vaskofea12c62020-03-30 11:00:15 +02002006 }
2007
Michal Vasko2f03d222020-12-09 18:15:51 +01002008 assert(op_iter);
Michal Vaskobb844672020-07-03 11:06:12 +02002009 *op_subtree = (struct lyd_node *)op_iter;
Michal Vasko2f03d222020-12-09 18:15:51 +01002010 if (!tree || tree_iter) {
2011 /* there is no tree whatsoever or this is the last found sibling */
2012 *tree_sibling = (struct lyd_node *)tree_iter;
2013 } else {
2014 /* matching parent was found but it has no children to insert next to */
2015 assert(match);
2016 *tree_parent = match;
2017 }
Michal Vaskocb7526d2020-03-30 15:08:26 +02002018}
2019
Michal Vaskoe0665742021-02-11 11:08:44 +01002020/**
2021 * @brief Validate an RPC/action request, reply, or notification.
2022 *
2023 * @param[in] op_tree Full operation data tree.
2024 * @param[in] op_node Operation node itself.
2025 * @param[in] dep_tree Tree to be used for validating references from the operation subtree.
2026 * @param[in] int_opts Internal parser options.
Michal Vaskofbbea932022-06-07 11:00:55 +02002027 * @param[in] data_type Type of validated data.
Michal Vaskoe0665742021-02-11 11:08:44 +01002028 * @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
2029 * @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
2030 * @param[in] node_types_p Set of unres node types, if NULL a local set is used.
2031 * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
Michal Vasko135719f2022-08-25 12:18:17 +02002032 * @param[in] ext_node_p Set of unres nodes with extensions to validate, if NULL a local set is used.
Michal Vaskoddd76592022-01-17 13:34:48 +01002033 * @param[in] ext_val_p Set of parsed extension data to validate, if NULL a local set is used.
Michal Vaskoe0665742021-02-11 11:08:44 +01002034 * @param[out] diff Optional diff with any changes made by the validation.
2035 * @return LY_SUCCESS on success.
2036 * @return LY_ERR error on error.
2037 */
2038static LY_ERR
Michal Vaskofbbea932022-06-07 11:00:55 +02002039_lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree, enum lyd_type data_type,
Michal Vaskoddd76592022-01-17 13:34:48 +01002040 uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p,
Michal Vasko135719f2022-08-25 12:18:17 +02002041 struct ly_set *meta_types_p, struct ly_set *ext_node_p, struct ly_set *ext_val_p, struct lyd_node **diff)
Michal Vaskocb7526d2020-03-30 15:08:26 +02002042{
Michal Vaskoe0665742021-02-11 11:08:44 +01002043 LY_ERR rc = LY_SUCCESS;
Michal Vaskofbbea932022-06-07 11:00:55 +02002044 struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *op_sibling_before, *op_sibling_after, *child;
Michal Vasko135719f2022-08-25 12:18:17 +02002045 struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_node = {0}, ext_val = {0};
Michal Vaskocb7526d2020-03-30 15:08:26 +02002046
Michal Vaskoe0665742021-02-11 11:08:44 +01002047 assert(op_tree && op_node);
Michal Vasko135719f2022-08-25 12:18:17 +02002048 assert((node_when_p && node_types_p && meta_types_p && ext_node_p && ext_val_p) ||
2049 (!node_when_p && !node_types_p && !meta_types_p && !ext_node_p && !ext_val_p));
Michal Vaskoe0665742021-02-11 11:08:44 +01002050
2051 if (!node_when_p) {
2052 node_when_p = &node_when;
2053 node_types_p = &node_types;
2054 meta_types_p = &meta_types;
Michal Vasko135719f2022-08-25 12:18:17 +02002055 ext_node_p = &ext_node;
Michal Vaskoddd76592022-01-17 13:34:48 +01002056 ext_val_p = &ext_val;
Michal Vaskoe0665742021-02-11 11:08:44 +01002057 }
2058
2059 /* merge op_tree into dep_tree */
2060 lyd_val_op_merge_find(op_tree, op_node, dep_tree, &op_subtree, &tree_sibling, &tree_parent);
Michal Vaskoc61dd062022-06-07 11:01:28 +02002061 op_sibling_before = op_subtree->prev->next ? op_subtree->prev : NULL;
2062 op_sibling_after = op_subtree->next;
Michal Vaskoe0665742021-02-11 11:08:44 +01002063 op_parent = lyd_parent(op_subtree);
Michal Vaskoc61dd062022-06-07 11:01:28 +02002064
Michal Vasko2e784f82024-01-11 09:51:22 +01002065 lyd_unlink(op_subtree);
aPiecek1462ab12024-02-07 09:13:29 +01002066 lyd_insert_node(tree_parent, &tree_sibling, op_subtree, LYD_INSERT_NODE_DEFAULT);
Michal Vaskoe0665742021-02-11 11:08:44 +01002067 if (!dep_tree) {
2068 dep_tree = tree_sibling;
2069 }
2070
Michal Vaskoe0665742021-02-11 11:08:44 +01002071 if (int_opts & LYD_INTOPT_REPLY) {
2072 /* add output children defaults */
Michal Vaskoddd76592022-01-17 13:34:48 +01002073 rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_types_p,
Michal Vaskofcbd78f2022-08-26 08:34:15 +02002074 ext_node_p, LYD_IMPLICIT_OUTPUT, diff);
Michal Vaskoe0665742021-02-11 11:08:44 +01002075 LY_CHECK_GOTO(rc, cleanup);
2076
2077 if (validate_subtree) {
2078 /* skip validating the operation itself, go to children directly */
2079 LY_LIST_FOR(lyd_child(op_node), child) {
Michal Vasko1a6e6902022-08-26 08:35:09 +02002080 rc = lyd_validate_subtree(child, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p, 0, diff);
Radek Krejci4f2e3e52021-03-30 14:20:28 +02002081 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01002082 }
2083 }
2084 } else {
2085 if (validate_subtree) {
2086 /* prevalidate whole operation subtree */
Michal Vasko1a6e6902022-08-26 08:35:09 +02002087 rc = lyd_validate_subtree(op_node, node_when_p, node_types_p, meta_types_p, ext_node_p, ext_val_p, 0, diff);
Radek Krejci4f2e3e52021-03-30 14:20:28 +02002088 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01002089 }
2090 }
2091
Michal Vasko906bafa2022-04-22 12:28:55 +02002092 /* finish incompletely validated terminal values/attributes and when conditions on the full tree,
2093 * account for unresolved 'when' that may appear in the non-validated dependency data tree */
Michal Vaskofbbea932022-06-07 11:00:55 +02002094 LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, node_when_p, LYXP_IGNORE_WHEN,
Michal Vasko135719f2022-08-25 12:18:17 +02002095 node_types_p, meta_types_p, ext_node_p, ext_val_p, 0, diff), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01002096
2097 /* perform final validation of the operation/notification */
2098 lyd_validate_obsolete(op_node);
Michal Vaskod027f382023-02-10 09:13:25 +01002099 LY_CHECK_GOTO(rc = lyd_validate_must(op_node, 0, int_opts, LYXP_IGNORE_WHEN), cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01002100
2101 /* final validation of all the descendants */
Michal Vasko906bafa2022-04-22 12:28:55 +02002102 rc = lyd_validate_final_r(lyd_child(op_node), op_node, op_node->schema, NULL, 0, int_opts, LYXP_IGNORE_WHEN);
2103 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoe0665742021-02-11 11:08:44 +01002104
2105cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01002106 /* restore operation tree */
Michal Vasko2e784f82024-01-11 09:51:22 +01002107 lyd_unlink(op_subtree);
Michal Vaskoc61dd062022-06-07 11:01:28 +02002108 if (op_sibling_before) {
aPiecek743184b2024-02-01 13:25:56 +01002109 lyd_insert_after_node(NULL, op_sibling_before, op_subtree);
Michal Vasko123f1c02023-08-15 13:14:46 +02002110 lyd_insert_hash(op_subtree);
Michal Vaskoc61dd062022-06-07 11:01:28 +02002111 } else if (op_sibling_after) {
2112 lyd_insert_before_node(op_sibling_after, op_subtree);
Michal Vasko123f1c02023-08-15 13:14:46 +02002113 lyd_insert_hash(op_subtree);
Michal Vaskoc61dd062022-06-07 11:01:28 +02002114 } else if (op_parent) {
aPiecek1462ab12024-02-07 09:13:29 +01002115 lyd_insert_node(op_parent, NULL, op_subtree, LYD_INSERT_NODE_DEFAULT);
Michal Vaskoe0665742021-02-11 11:08:44 +01002116 }
2117
2118 ly_set_erase(&node_when, NULL);
2119 ly_set_erase(&node_types, NULL);
2120 ly_set_erase(&meta_types, NULL);
Michal Vasko135719f2022-08-25 12:18:17 +02002121 ly_set_erase(&ext_node, free);
Michal Vaskoddd76592022-01-17 13:34:48 +01002122 ly_set_erase(&ext_val, free);
Michal Vaskoe0665742021-02-11 11:08:44 +01002123 return rc;
2124}
2125
Jan Kundrátc53a7ec2021-12-09 16:01:19 +01002126LIBYANG_API_DEF LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +01002127lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *dep_tree, enum lyd_type data_type, struct lyd_node **diff)
2128{
2129 struct lyd_node *op_node;
2130 uint32_t int_opts;
Michal Vaskofbbea932022-06-07 11:00:55 +02002131 struct ly_set ext_val = {0};
2132 LY_ERR rc;
Michal Vaskoe0665742021-02-11 11:08:44 +01002133
Michal Vasko2da45692022-04-29 09:51:08 +02002134 LY_CHECK_ARG_RET(NULL, op_tree, !dep_tree || !dep_tree->parent, (data_type == LYD_TYPE_RPC_YANG) ||
Michal Vasko1e4c68e2021-02-18 15:03:01 +01002135 (data_type == LYD_TYPE_NOTIF_YANG) || (data_type == LYD_TYPE_REPLY_YANG), LY_EINVAL);
Michal Vasko8104fd42020-07-13 11:09:51 +02002136 if (diff) {
2137 *diff = NULL;
2138 }
Michal Vasko1e4c68e2021-02-18 15:03:01 +01002139 if (data_type == LYD_TYPE_RPC_YANG) {
Michal Vaskoe0665742021-02-11 11:08:44 +01002140 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION;
Michal Vasko1e4c68e2021-02-18 15:03:01 +01002141 } else if (data_type == LYD_TYPE_NOTIF_YANG) {
Michal Vaskoe0665742021-02-11 11:08:44 +01002142 int_opts = LYD_INTOPT_NOTIF;
2143 } else {
2144 int_opts = LYD_INTOPT_REPLY;
2145 }
Michal Vaskocb7526d2020-03-30 15:08:26 +02002146
Michal Vasko2da45692022-04-29 09:51:08 +02002147 if (op_tree->schema && (op_tree->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
2148 /* we have the operation/notification, adjust the pointers */
2149 op_node = op_tree;
2150 while (op_tree->parent) {
2151 op_tree = lyd_parent(op_tree);
Michal Vaskocb7526d2020-03-30 15:08:26 +02002152 }
Michal Vasko2da45692022-04-29 09:51:08 +02002153 } else {
2154 /* find the operation/notification */
2155 while (op_tree->parent) {
2156 op_tree = lyd_parent(op_tree);
2157 }
2158 LYD_TREE_DFS_BEGIN(op_tree, op_node) {
2159 if (!op_node->schema) {
Michal Vaskoac6f4be2022-05-02 10:16:50 +02002160 return lyd_parse_opaq_error(op_node);
Michal Vaskofbbea932022-06-07 11:00:55 +02002161 } else if (op_node->flags & LYD_EXT) {
2162 /* fully validate the rest using the extension instance callback */
2163 LY_CHECK_RET(lyd_validate_nested_ext(op_node, &ext_val));
Michal Vasko135719f2022-08-25 12:18:17 +02002164 rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, NULL, 0, NULL, NULL, NULL,
2165 &ext_val, 0, diff);
Michal Vaskofbbea932022-06-07 11:00:55 +02002166 ly_set_erase(&ext_val, free);
2167 return rc;
Michal Vasko2da45692022-04-29 09:51:08 +02002168 }
2169
2170 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) &&
2171 (op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
2172 break;
2173 } else if ((int_opts & LYD_INTOPT_NOTIF) && (op_node->schema->nodetype == LYS_NOTIF)) {
2174 break;
2175 }
2176 LYD_TREE_DFS_END(op_tree, op_node);
2177 }
Michal Vaskocb7526d2020-03-30 15:08:26 +02002178 }
Michal Vasko2da45692022-04-29 09:51:08 +02002179
Michal Vaskoe0665742021-02-11 11:08:44 +01002180 if (int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) {
Michal Vasko9b232082022-06-07 10:59:31 +02002181 if (!op_node || !(op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02002182 LOGERR(LYD_CTX(op_tree), LY_EINVAL, "No RPC/action to validate found.");
Michal Vaskocb7526d2020-03-30 15:08:26 +02002183 return LY_EINVAL;
2184 }
2185 } else {
Michal Vasko9b232082022-06-07 10:59:31 +02002186 if (!op_node || (op_node->schema->nodetype != LYS_NOTIF)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +02002187 LOGERR(LYD_CTX(op_tree), LY_EINVAL, "No notification to validate found.");
Michal Vaskocb7526d2020-03-30 15:08:26 +02002188 return LY_EINVAL;
2189 }
2190 }
2191
Michal Vaskoe0665742021-02-11 11:08:44 +01002192 /* validate */
Michal Vasko135719f2022-08-25 12:18:17 +02002193 return _lyd_validate_op(op_tree, op_node, dep_tree, data_type, int_opts, 1, NULL, NULL, NULL, NULL, NULL, diff);
Michal Vaskofea12c62020-03-30 11:00:15 +02002194}