Coverage Report

Created: 2026-06-10 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/validation.c
Line
Count
Source
1
/**
2
 * @file validation.c
3
 * @author Michal Vasko <mvasko@cesnet.cz>
4
 * @brief Validation
5
 *
6
 * Copyright (c) 2019 - 2026 CESNET, z.s.p.o.
7
 *
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
 */
14
#define _GNU_SOURCE /* asprintf, strdup */
15
16
#include "validation.h"
17
18
#include <assert.h>
19
#include <limits.h>
20
#include <stdint.h>
21
#include <stdio.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "compat.h"
26
#include "dict.h"
27
#include "diff.h"
28
#include "hash_table.h"
29
#include "log.h"
30
#include "ly_common.h"
31
#include "parser_data.h"
32
#include "parser_internal.h"
33
#include "plugins_exts.h"
34
#include "plugins_exts/metadata.h"
35
#include "plugins_internal.h"
36
#include "plugins_types.h"
37
#include "set.h"
38
#include "tree.h"
39
#include "tree_data.h"
40
#include "tree_data_internal.h"
41
#include "tree_schema.h"
42
#include "tree_schema_internal.h"
43
#include "xpath.h"
44
45
/**
46
 * @brief Check validation error taking into account multi-error validation.
47
 *
48
 * @param[in] r Local return value.
49
 * @param[in] err_cmd Command to perform on any error.
50
 * @param[in] val_opts Validation options.
51
 * @param[in] label Label to go to on fatal error.
52
 */
53
#define LY_VAL_ERR_GOTO(r, err_cmd, val_opts, label) \
54
0
        if (r) { \
55
0
            err_cmd; \
56
0
            if ((r != LY_EVALID) || !(val_opts & LYD_VALIDATE_MULTI_ERROR)) { \
57
0
                goto label; \
58
0
            } \
59
0
        }
60
61
/**
62
 * @brief Callback for freeing getnext HT values.
63
 */
64
static void
65
lyd_val_getnext_ht_free_cb(void *val_p)
66
0
{
67
0
    struct lyd_val_getnext *val = val_p;
68
69
0
    free(val->snodes);
70
0
    free(val->choices);
71
0
}
72
73
/**
74
 * @brief Callback for checking getnext HT value equality.
75
 */
76
static ly_bool
77
lyd_val_getnext_ht_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data))
78
0
{
79
0
    struct lyd_val_getnext *val1 = val1_p;
80
0
    struct lyd_val_getnext *val2 = val2_p;
81
82
0
    if (val1->sparent == val2->sparent) {
83
0
        return 1;
84
0
    }
85
0
    return 0;
86
0
}
87
88
LY_ERR
89
lyd_val_getnext_ht_new(struct ly_ht **getnext_ht_p)
90
0
{
91
0
    *getnext_ht_p = lyht_new(32, sizeof(struct lyd_val_getnext), lyd_val_getnext_ht_equal_cb, NULL, 1);
92
93
0
    if (!*getnext_ht_p) {
94
0
        LOGMEM(NULL);
95
0
        return LY_EMEM;
96
0
    }
97
0
    return LY_SUCCESS;
98
0
}
99
100
void
101
lyd_val_getnext_ht_free(struct ly_ht *getnext_ht)
102
0
{
103
0
    lyht_free(getnext_ht, lyd_val_getnext_ht_free_cb);
104
0
}
105
106
/**
107
 * @brief Wrapper of ::lyd_val_getnext_ht_free() to be used as a set item destructor.
108
 *
109
 * @param[in] getnext_ht Getnext HT to free.
110
 */
111
static void
112
lyd_val_getnext_ht_set_free(void *getnext_ht)
113
0
{
114
0
    lyd_val_getnext_ht_free(getnext_ht);
115
0
}
116
117
LY_ERR
118
lyd_val_getnext_get(const struct lysc_node *snode, const struct lysc_node *sparent, const struct lys_module *mod,
119
        ly_bool output, struct ly_ht *getnext_ht, const struct lysc_node ***choices, const struct lysc_node ***snodes)
120
0
{
121
0
    LY_ERR rc = LY_SUCCESS;
122
0
    struct lyd_val_getnext val = {0}, *getnext = NULL;
123
0
    uint32_t getnext_opts, snode_count = 0, choice_count = 0;
124
125
0
    assert(snode || sparent || mod);
126
127
    /* try to find the entry for this schema parent */
128
0
    val.sparent = sparent;
129
0
    if (!lyht_find(getnext_ht, &val, (uintptr_t)sparent, (void **)&getnext)) {
130
0
        goto cleanup;
131
0
    }
132
133
0
    getnext_opts = LYS_GETNEXT_WITHCHOICE | (output ? LYS_GETNEXT_OUTPUT : 0);
134
135
    /* get the first schema node, need to prefer sparent or mod (for choices) */
136
0
    if (sparent || mod) {
137
0
        snode = lys_getnext(NULL, sparent, mod ? mod->compiled : NULL, getnext_opts);
138
0
    } else {
139
0
        while (snode->prev->next) {
140
0
            snode = snode->prev;
141
0
        }
142
0
    }
143
144
    /* traverse all the children using getnext and store them */
145
0
    while (snode) {
146
0
        if (snode->nodetype == LYS_CHOICE) {
147
            /* store a choice node */
148
0
            val.choices = ly_realloc(val.choices, (choice_count + 2) * sizeof *val.choices);
149
0
            LY_CHECK_ERR_GOTO(!val.choices, LOGMEM(NULL); rc = LY_EMEM, cleanup);
150
0
            val.choices[choice_count] = snode;
151
0
            ++choice_count;
152
0
        } else {
153
            /* store other nodes */
154
0
            val.snodes = ly_realloc(val.snodes, (snode_count + 2) * sizeof *val.snodes);
155
0
            LY_CHECK_ERR_GOTO(!val.snodes, LOGMEM(NULL); rc = LY_EMEM, cleanup);
156
0
            val.snodes[snode_count] = snode;
157
0
            ++snode_count;
158
0
        }
159
160
0
        snode = lys_getnext(snode, sparent, mod ? mod->compiled : NULL, getnext_opts);
161
0
    }
162
163
    /* add terminating NULL items */
164
0
    if (choice_count) {
165
0
        val.choices[choice_count] = NULL;
166
0
    }
167
0
    if (snode_count) {
168
0
        val.snodes[snode_count] = NULL;
169
0
    }
170
171
    /* add into the hash table */
172
0
    if ((rc = lyht_insert(getnext_ht, &val, (uintptr_t)sparent, (void **)&getnext))) {
173
0
        goto cleanup;
174
0
    }
175
176
0
cleanup:
177
0
    if (rc) {
178
0
        free(val.snodes);
179
0
        free(val.choices);
180
0
    } else {
181
0
        *choices = getnext->choices;
182
0
        *snodes = getnext->snodes;
183
0
    }
184
0
    return rc;
185
0
}
186
187
LY_ERR
188
lyd_val_diff_add(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_node **diff)
189
0
{
190
0
    LY_ERR ret = LY_SUCCESS;
191
0
    struct lyd_node *new_diff = NULL;
192
0
    const struct lyd_node *prev_inst;
193
0
    char *key = NULL, *value = NULL, *position = NULL;
194
0
    size_t buflen = 0, bufused = 0;
195
0
    uint32_t pos;
196
197
0
    assert((op == LYD_DIFF_OP_DELETE) || (op == LYD_DIFF_OP_CREATE));
198
199
0
    if ((op == LYD_DIFF_OP_CREATE) && lysc_is_userordered(node->schema)) {
200
0
        if (lysc_is_dup_inst_list(node->schema)) {
201
0
            pos = lyd_list_pos(node);
202
203
            /* generate position meta */
204
0
            if (pos > 1) {
205
0
                if (asprintf(&position, "%" PRIu32, pos - 1) == -1) {
206
0
                    LOGMEM(LYD_CTX(node));
207
0
                    ret = LY_EMEM;
208
0
                    goto cleanup;
209
0
                }
210
0
            } else {
211
0
                position = strdup("");
212
0
                LY_CHECK_ERR_GOTO(!position, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
213
0
            }
214
0
        } else {
215
0
            if (node->prev->next && (node->prev->schema == node->schema)) {
216
0
                prev_inst = node->prev;
217
0
            } else {
218
                /* first instance */
219
0
                prev_inst = NULL;
220
0
            }
221
222
0
            if (node->schema->nodetype == LYS_LIST) {
223
                /* generate key meta */
224
0
                if (prev_inst) {
225
0
                    LY_CHECK_GOTO(ret = lyd_path_list_predicate(prev_inst, &key, &buflen, &bufused, 0), cleanup);
226
0
                } else {
227
0
                    key = strdup("");
228
0
                    LY_CHECK_ERR_GOTO(!key, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
229
0
                }
230
0
            } else {
231
                /* generate value meta */
232
0
                if (prev_inst) {
233
0
                    value = strdup(lyd_get_value(prev_inst));
234
0
                    LY_CHECK_ERR_GOTO(!value, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
235
0
                } else {
236
0
                    value = strdup("");
237
0
                    LY_CHECK_ERR_GOTO(!value, LOGMEM(LYD_CTX(node)); ret = LY_EMEM, cleanup);
238
0
                }
239
0
            }
240
0
        }
241
0
    }
242
243
    /* create new diff tree */
244
0
    LY_CHECK_GOTO(ret = lyd_diff_add(node, op, NULL, NULL, key, value, position, NULL, NULL, &new_diff, NULL), cleanup);
245
246
    /* merge into existing diff */
247
0
    ret = lyd_diff_merge_all(diff, new_diff, 0);
248
249
0
cleanup:
250
0
    lyd_free_tree(new_diff);
251
0
    free(key);
252
0
    free(value);
253
0
    free(position);
254
0
    return ret;
255
0
}
256
257
/**
258
 * @brief Evaluate all relevant "when" conditions of a node.
259
 *
260
 * @param[in] tree Data tree.
261
 * @param[in] node Node whose relevant when conditions will be evaluated.
262
 * @param[in] schema Schema node of @p node. It may not be possible to use directly if @p node is opaque.
263
 * @param[in] xpath_opts Additional XPath options to use.
264
 * @param[out] disabled First when that evaluated false, if any.
265
 * @return LY_SUCCESS on success.
266
 * @return LY_EINCOMPLETE if a referenced node does not have its when evaluated.
267
 * @return LY_ERR value on error.
268
 */
269
static LY_ERR
270
lyd_validate_node_when(const struct lyd_node *tree, const struct lyd_node *node, const struct lysc_node *schema,
271
        uint32_t xpath_opts, const struct lysc_when **disabled)
272
0
{
273
0
    LY_ERR r;
274
0
    const struct lyd_node *ctx_node;
275
0
    struct lyxp_set xp_set;
276
0
    LY_ARRAY_COUNT_TYPE u;
277
278
0
    assert(!node->schema || (node->schema == schema));
279
280
0
    *disabled = NULL;
281
282
0
    do {
283
0
        const struct lysc_when *when;
284
0
        struct lysc_when **when_list = lysc_node_when(schema);
285
286
0
        LY_ARRAY_FOR(when_list, u) {
287
0
            when = when_list[u];
288
289
            /* get context node */
290
0
            if (when->context == schema) {
291
0
                ctx_node = node;
292
0
            } else {
293
0
                assert((!when->context && !node->parent) || (when->context == node->parent->schema));
294
0
                ctx_node = node->parent;
295
0
            }
296
297
            /* evaluate when */
298
0
            memset(&xp_set, 0, sizeof xp_set);
299
0
            r = lyxp_eval(LYD_CTX(node), when->cond, schema->module, LY_VALUE_SCHEMA_RESOLVED, when->prefixes,
300
0
                    ctx_node, ctx_node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_opts);
301
0
            lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
302
303
            /* return error or LY_EINCOMPLETE for dependant unresolved when */
304
0
            LY_CHECK_RET(r);
305
306
0
            if (!xp_set.val.bln) {
307
                /* false when */
308
0
                *disabled = when;
309
0
                return LY_SUCCESS;
310
0
            }
311
0
        }
312
313
0
        schema = schema->parent;
314
0
    } while (schema && (schema->nodetype & (LYS_CASE | LYS_CHOICE)));
315
316
0
    return LY_SUCCESS;
317
0
}
318
319
/**
320
 * @brief Properly delete a node as part of auto-delete validation tasks.
321
 *
322
 * @param[in,out] first First sibling, is updated if needed.
323
 * @param[in] del Node instance to delete.
324
 * @param[in] mod Module of the siblings, NULL for nested siblings.
325
 * @param[in] np_cont_diff Whether to put NP container into diff or only its children.
326
 * @param[in,out] node Optional current iteration node, update it if it is deleted.
327
 * @param[in,out] node_when Optional set with nodes with "when" conditions, may be removed from.
328
 * @param[in,out] node_types Optional set with unresolved type nodes, may be removed from.
329
 * @param[in,out] diff Validation diff.
330
 * @return 1 if @p node auto-deleted and updated to its next sibling.
331
 * @return 0 if @p node was not auto-deleted.
332
 */
333
static ly_bool
334
lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, const struct lys_module *mod,
335
        int np_cont_diff, struct lyd_node **node, struct ly_set *node_when, struct ly_set *node_types, struct lyd_node **diff)
336
0
{
337
0
    struct lyd_node *iter;
338
0
    ly_bool node_autodel = 0;
339
0
    uint32_t idx;
340
341
    /* update pointers */
342
0
    lyd_del_move_root(first, del, mod);
343
0
    if (node && (del == *node)) {
344
0
        *node = (*node)->next;
345
0
        node_autodel = 1;
346
0
    }
347
348
0
    if (diff) {
349
        /* add into diff */
350
0
        if (!np_cont_diff && (del->schema->nodetype == LYS_CONTAINER) && !(del->schema->flags & LYS_PRESENCE)) {
351
            /* we do not want to track NP container changes, but remember any removed children */
352
0
            LY_LIST_FOR(lyd_child(del), iter) {
353
0
                lyd_val_diff_add(iter, LYD_DIFF_OP_DELETE, diff);
354
0
            }
355
0
        } else {
356
0
            lyd_val_diff_add(del, LYD_DIFF_OP_DELETE, diff);
357
0
        }
358
0
    }
359
360
0
    if (node_when && node_when->count) {
361
        /* remove nested from node_when set */
362
0
        LYD_TREE_DFS_BEGIN(del, iter) {
363
0
            if ((del != iter) && ly_set_contains(node_when, iter, &idx)) {
364
0
                assert(0 && "Please contact libyang support with the use-case that triggered this assert.");
365
                // ly_set_rm_index(node_when, idx, NULL);
366
0
            }
367
0
            LYD_TREE_DFS_END(del, iter);
368
0
        }
369
0
    }
370
371
0
    if (node_types && node_types->count) {
372
        /* remove from node_types set */
373
0
        LYD_TREE_DFS_BEGIN(del, iter) {
374
0
            if ((iter->schema->nodetype & LYD_NODE_TERM) &&
375
0
                    LYSC_GET_TYPE_PLG(((struct lysc_node_leaf *)iter->schema)->type->plugin_ref)->validate_tree &&
376
0
                    ly_set_contains(node_types, iter, &idx)) {
377
0
                ly_set_rm_index(node_types, idx, NULL);
378
0
            }
379
0
            LYD_TREE_DFS_END(del, iter);
380
0
        }
381
0
    }
382
383
    /* free */
384
0
    lyd_free_tree(del);
385
386
0
    return node_autodel;
387
0
}
388
389
/**
390
 * @brief Evaluate when conditions of collected unres nodes.
391
 *
392
 * @param[in,out] tree Data tree, is updated if some nodes are autodeleted.
393
 * @param[in] mod Module of the @p tree to take into consideration when deleting @p tree and moving it.
394
 * If set, it is expected @p tree should point to the first node of @p mod. Otherwise it will simply be
395
 * the first top-level sibling.
396
 * @param[in] node_when Set with nodes with "when" conditions.
397
 * @param[in] val_opts Validation options.
398
 * @param[in] xpath_options Additional XPath options to use.
399
 * @param[in,out] node_types Set with nodes with unresolved types, remove any with false "when" parents.
400
 * @param[in,out] diff Validation diff.
401
 * @return LY_SUCCESS on success.
402
 * @return LY_ERR value on error.
403
 */
404
static LY_ERR
405
lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, struct ly_set *node_when,
406
        uint32_t val_opts, uint32_t xpath_options, struct ly_set *node_types, struct lyd_node **diff)
407
0
{
408
0
    LY_ERR rc = LY_SUCCESS, r;
409
0
    uint32_t i, count;
410
0
    const struct lysc_when *disabled;
411
0
    struct lyd_node *node = NULL;
412
413
0
    if (!node_when->count) {
414
0
        return LY_SUCCESS;
415
0
    }
416
417
0
    i = node_when->count;
418
0
    do {
419
0
        --i;
420
0
        node = node_when->dnodes[i];
421
422
        /* evaluate all when expressions that affect this node's existence */
423
0
        r = lyd_validate_node_when(*tree, node, node->schema, xpath_options, &disabled);
424
0
        if (!r) {
425
0
            if (disabled) {
426
                /* when false */
427
0
                if (node->flags & LYD_WHEN_TRUE) {
428
                    /* autodelete */
429
0
                    count = node_when->count;
430
0
                    lyd_validate_autodel_node_del(tree, node, mod, 1, NULL, node_when, node_types, diff);
431
0
                    if (count > node_when->count) {
432
                        /* nested nodes removed, we lost the index */
433
0
                        ly_set_contains(node_when, node, &i);
434
0
                    }
435
0
                } else if (val_opts & LYD_VALIDATE_OPERATIONAL) {
436
                    /* only a warning */
437
0
                    LOGWRN(LYD_CTX(node), "When condition \"%s\" not satisfied.", disabled->cond->expr);
438
0
                } else {
439
                    /* invalid data */
440
0
                    LOGVAL(LYD_CTX(node), node, LY_VCODE_NOWHEN, disabled->cond->expr);
441
0
                    r = LY_EVALID;
442
0
                    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
443
0
                }
444
0
            } else {
445
                /* when true */
446
0
                node->flags |= LYD_WHEN_TRUE;
447
0
            }
448
449
            /* remove this node from the set keeping the order, its when was resolved */
450
0
            ly_set_rm_index_ordered(node_when, i, NULL);
451
0
        } else if (r != LY_EINCOMPLETE) {
452
            /* error */
453
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
454
0
        }
455
0
    } while (i);
456
457
0
cleanup:
458
0
    return rc;
459
0
}
460
461
LY_ERR
462
lyd_validate_unres(struct lyd_node **tree, const struct lys_module *mod, enum lyd_type data_type,
463
        struct ly_set *node_when, uint32_t when_xp_opts, struct ly_set *node_types, struct ly_set *meta_types,
464
        struct ly_set *ext_val, uint32_t val_opts, struct lyd_node **diff)
465
0
{
466
0
    LY_ERR r, rc = LY_SUCCESS;
467
0
    uint32_t i;
468
469
0
    if (ext_val && ext_val->count) {
470
        /* first validate parsed extension data */
471
0
        i = ext_val->count;
472
0
        do {
473
0
            --i;
474
475
0
            struct lyd_ctx_ext_val *ext_v = ext_val->objs[i];
476
477
            /* validate extension data */
478
0
            r = LYSC_GET_EXT_PLG(ext_v->ext->def->plugin_ref)->validate(ext_v->ext, ext_v->sibling, *tree,
479
0
                    data_type, val_opts, diff);
480
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
481
482
            /* remove this item from the set */
483
0
            ly_set_rm_index(ext_val, i, free);
484
0
        } while (i);
485
0
    }
486
487
0
    if (node_when) {
488
        /* evaluate all when conditions */
489
0
        uint32_t prev_count;
490
491
0
        do {
492
0
            prev_count = node_when->count;
493
0
            r = lyd_validate_unres_when(tree, mod, node_when, val_opts, when_xp_opts, node_types, diff);
494
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
495
496
            /* there must have been some when conditions resolved */
497
0
        } while (prev_count > node_when->count);
498
499
0
        if (node_when->count) {
500
            /* there could have been no cyclic when dependencies, checked during compilation */
501
0
            assert((rc == LY_EVALID) && (val_opts & LYD_VALIDATE_MULTI_ERROR));
502
503
            /* when condition was validated and it is not satisfied, error printed, if kept in the set the following
504
             * unres (for the next module) can fail this assert */
505
0
            ly_set_erase(node_when, NULL);
506
0
        }
507
0
    }
508
509
0
    if (node_types && node_types->count) {
510
        /* finish incompletely validated terminal values (traverse from the end for efficient set removal) */
511
0
        i = node_types->count;
512
0
        do {
513
0
            --i;
514
515
0
            struct lyd_node_term *node = node_types->objs[i];
516
0
            struct lysc_type *type = ((struct lysc_node_leaf *)node->schema)->type;
517
518
            /* resolve the value of the node */
519
0
            r = lyd_value_validate_incomplete(LYD_CTX(node), type, &node->value, &node->node, *tree);
520
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
521
522
            /* remove this node from the set */
523
0
            ly_set_rm_index(node_types, i, NULL);
524
0
        } while (i);
525
0
    }
526
527
0
    if (meta_types && meta_types->count) {
528
        /* ... and metadata values */
529
0
        i = meta_types->count;
530
0
        do {
531
0
            --i;
532
533
0
            struct lyd_meta *meta = meta_types->objs[i];
534
0
            struct lysc_type *type;
535
536
            /* validate and store the value of the metadata */
537
0
            lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
538
0
            r = lyd_value_validate_incomplete(LYD_CTX(meta->parent), type, &meta->value, meta->parent, *tree);
539
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
540
541
            /* remove this attr from the set */
542
0
            ly_set_rm_index(meta_types, i, NULL);
543
0
        } while (i);
544
0
    }
545
546
0
cleanup:
547
0
    return rc;
548
0
}
549
550
/**
551
 * @brief Compare callback for finding duplicates in hash table.
552
 *
553
 * Implementation of ::lyht_value_equal_cb.
554
 */
555
static ly_bool
556
lyd_val_dup_val_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *cb_data)
557
0
{
558
    /* always find the same instance, not the exact same pointer (set mod = 0) */
559
0
    return lyd_hash_table_val_equal(val1_p, val2_p, 0, cb_data);
560
0
}
561
562
/**
563
 * @brief Validate instance duplication.
564
 *
565
 * @param[in] first First sibling to search in.
566
 * @param[in] node Data node instance to check.
567
 * @param[in] val_opts Validation options.
568
 * @return LY_ERR value.
569
 */
570
static LY_ERR
571
lyd_validate_duplicates(const struct lyd_node *first, const struct lyd_node *node, uint32_t val_opts)
572
0
{
573
0
    ly_bool fail = 0;
574
575
0
    assert(node->flags & LYD_NEW);
576
577
    /* key-less list or non-configuration leaf-list */
578
0
    if (lysc_is_dup_inst_list(node->schema)) {
579
        /* duplicate instances allowed */
580
0
        return LY_SUCCESS;
581
0
    }
582
583
    /* find exactly the same next instance using hashes if possible */
584
0
    if (node->parent && ((struct lyd_node_inner *)node->parent)->children_ht) {
585
        /* because of the callback used, an instance must always be found (pointer may or may not be equal to node),
586
         * so if we find another instance, there is a duplicate */
587
0
        if (!lyht_find_next_with_collision_cb(((struct lyd_node_inner *)node->parent)->children_ht, &node, node->hash,
588
0
                lyd_val_dup_val_equal, NULL)) {
589
0
            fail = 1;
590
0
        }
591
0
    } else {
592
0
        for ( ; first; first = first->next) {
593
0
            if (first == node) {
594
0
                continue;
595
0
            }
596
597
0
            if (node->schema->nodetype & (LYD_NODE_ANY | LYS_LEAF)) {
598
0
                if (first->schema == node->schema) {
599
0
                    fail = 1;
600
0
                    break;
601
0
                }
602
0
            } else if (!lyd_compare_single(first, node, 0)) {
603
0
                fail = 1;
604
0
                break;
605
0
            }
606
0
        }
607
0
    }
608
609
0
    if (fail) {
610
0
        if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (val_opts & LYD_VALIDATE_OPERATIONAL)) {
611
            /* only a warning */
612
0
            LOGWRN(LYD_CTX(node), "Duplicate instance of \"%s\".", node->schema->name);
613
0
        } else {
614
0
            LOGVAL(LYD_CTX(node), node, LY_VCODE_DUP, node->schema->name);
615
0
            return LY_EVALID;
616
0
        }
617
0
    }
618
0
    return LY_SUCCESS;
619
0
}
620
621
/**
622
 * @brief Validate multiple case data existence with possible autodelete.
623
 *
624
 * @param[in,out] first First sibling to search in, is updated if needed.
625
 * @param[in] mod Module of the siblings, NULL for nested siblings.
626
 * @param[in] choic Choice node whose cases to check.
627
 * @param[in,out] diff Validation diff.
628
 * @return LY_ERR value.
629
 */
630
static LY_ERR
631
lyd_validate_cases(struct lyd_node **first, const struct lys_module *mod, const struct lysc_node_choice *choic,
632
        struct lyd_node **diff)
633
0
{
634
0
    const struct lysc_node *scase, *iter, *old_case = NULL, *new_case = NULL;
635
0
    struct lyd_node *match, *to_del;
636
0
    ly_bool found;
637
638
0
    LY_LIST_FOR((struct lysc_node *)choic->cases, scase) {
639
0
        found = 0;
640
0
        iter = NULL;
641
0
        match = NULL;
642
0
        while ((match = lys_getnext_data(match, *first, &iter, scase, NULL))) {
643
0
            if (match->flags & LYD_NEW) {
644
                /* a new case data found, nothing more to look for */
645
0
                found = 2;
646
0
                break;
647
0
            } else {
648
                /* and old case data found */
649
0
                if (found == 0) {
650
0
                    found = 1;
651
0
                }
652
0
            }
653
0
        }
654
655
0
        if (found == 1) {
656
            /* there should not be 2 old cases */
657
0
            if (old_case) {
658
                /* old data from 2 cases */
659
0
                LOG_LOCSET(&choic->node);
660
0
                LOGVAL(choic->module->ctx, NULL, LY_VCODE_DUPCASE, old_case->name, scase->name);
661
0
                LOG_LOCBACK(1);
662
0
                return LY_EVALID;
663
0
            }
664
665
            /* remember an old existing case */
666
0
            old_case = scase;
667
0
        } else if (found == 2) {
668
0
            if (new_case) {
669
                /* new data from 2 cases */
670
0
                LOG_LOCSET(&choic->node);
671
0
                LOGVAL(choic->module->ctx, NULL, LY_VCODE_DUPCASE, new_case->name, scase->name);
672
0
                LOG_LOCBACK(1);
673
0
                return LY_EVALID;
674
0
            }
675
676
            /* remember a new existing case */
677
0
            new_case = scase;
678
0
        }
679
0
    }
680
681
0
    if (old_case && new_case) {
682
        /* auto-delete old case */
683
0
        iter = NULL;
684
0
        match = NULL;
685
0
        to_del = NULL;
686
0
        while ((match = lys_getnext_data(match, *first, &iter, old_case, NULL))) {
687
0
            lyd_del_move_root(first, to_del, mod);
688
689
            /* free previous node */
690
0
            lyd_free_tree(to_del);
691
0
            if (diff) {
692
                /* add into diff */
693
0
                LY_CHECK_RET(lyd_val_diff_add(match, LYD_DIFF_OP_DELETE, diff));
694
0
            }
695
0
            to_del = match;
696
0
        }
697
0
        lyd_del_move_root(first, to_del, mod);
698
0
        lyd_free_tree(to_del);
699
0
    }
700
701
0
    return LY_SUCCESS;
702
0
}
703
704
/**
705
 * @brief Check whether a schema node can have some default values (true for NP containers as well).
706
 *
707
 * @param[in] schema Schema node to check.
708
 * @return non-zero if yes,
709
 * @return 0 otherwise.
710
 */
711
static int
712
lyd_val_has_default(const struct lysc_node *schema)
713
0
{
714
0
    switch (schema->nodetype) {
715
0
    case LYS_LEAF:
716
0
        if (((struct lysc_node_leaf *)schema)->dflt.str) {
717
0
            return 1;
718
0
        }
719
0
        break;
720
0
    case LYS_LEAFLIST:
721
0
        if (((struct lysc_node_leaflist *)schema)->dflts) {
722
0
            return 1;
723
0
        }
724
0
        break;
725
0
    case LYS_CONTAINER:
726
0
        if (!(schema->flags & LYS_PRESENCE)) {
727
0
            return 1;
728
0
        }
729
0
        break;
730
0
    default:
731
0
        break;
732
0
    }
733
734
0
    return 0;
735
0
}
736
737
/**
738
 * @brief Auto-delete leaf-list default instances to prevent validation errors.
739
 *
740
 * @param[in,out] first First sibling to search in, is updated if needed.
741
 * @param[in,out] node New data node instance to check, is updated if auto-deleted.
742
 * @param[in] mod Module of the siblings, NULL for nested siblings.
743
 * @param[in,out] diff Validation diff.
744
 * @return 1 if @p node auto-deleted and updated to its next sibling.
745
 * @return 0 if @p node was not auto-deleted.
746
 */
747
static ly_bool
748
lyd_validate_autodel_leaflist_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
749
        struct lyd_node **diff)
750
0
{
751
0
    const struct lysc_node *schema;
752
0
    struct lyd_node *iter, *next;
753
0
    ly_bool found = 0, node_autodel = 0;
754
755
0
    assert((*node)->flags & LYD_NEW);
756
757
0
    schema = (*node)->schema;
758
0
    assert(schema->nodetype == LYS_LEAFLIST);
759
760
    /* check whether there is any explicit instance */
761
0
    LYD_LIST_FOR_INST(*first, schema, iter) {
762
0
        if (!(iter->flags & LYD_DEFAULT)) {
763
0
            found = 1;
764
0
            break;
765
0
        }
766
0
    }
767
0
    if (!found) {
768
        /* no explicit instance, keep defaults as they are */
769
0
        return 0;
770
0
    }
771
772
0
    LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
773
0
        if (iter->flags & LYD_DEFAULT) {
774
            /* default instance found, remove it */
775
0
            if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
776
0
                node_autodel = 1;
777
0
            }
778
0
        }
779
0
    }
780
781
0
    return node_autodel;
782
0
}
783
784
/**
785
 * @brief Auto-delete container or leaf default instances to prevent validation errors.
786
 *
787
 * @param[in,out] first First sibling to search in, is updated if needed.
788
 * @param[in,out] node New data node instance to check, is updated if auto-deleted.
789
 * @param[in] mod Module of the siblings, NULL for nested siblings.
790
 * @param[in,out] diff Validation diff.
791
 * @return 1 if @p node auto-deleted and updated to its next sibling.
792
 * @return 0 if @p node was not auto-deleted.
793
 */
794
static ly_bool
795
lyd_validate_autodel_cont_leaf_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
796
        struct lyd_node **diff)
797
0
{
798
0
    const struct lysc_node *schema;
799
0
    struct lyd_node *iter, *next;
800
0
    ly_bool found = 0, node_autodel = 0;
801
802
0
    assert((*node)->flags & LYD_NEW);
803
804
0
    schema = (*node)->schema;
805
0
    assert(schema->nodetype & (LYS_LEAF | LYS_CONTAINER));
806
807
    /* check whether there is any explicit instance */
808
0
    LYD_LIST_FOR_INST(*first, schema, iter) {
809
0
        if (!(iter->flags & LYD_DEFAULT)) {
810
0
            found = 1;
811
0
            break;
812
0
        }
813
0
    }
814
815
0
    if (found) {
816
        /* remove all default instances */
817
0
        LYD_LIST_FOR_INST_SAFE(*first, schema, next, iter) {
818
0
            if (iter->flags & LYD_DEFAULT) {
819
                /* default instance, remove it */
820
0
                if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
821
0
                    node_autodel = 1;
822
0
                }
823
0
            }
824
0
        }
825
0
    } else {
826
        /* remove a single old default instance, if any */
827
0
        LYD_LIST_FOR_INST(*first, schema, iter) {
828
0
            if ((iter->flags & LYD_DEFAULT) && !(iter->flags & LYD_NEW)) {
829
                /* old default instance, remove it */
830
0
                if (lyd_validate_autodel_node_del(first, iter, mod, 0, node, NULL, NULL, diff)) {
831
0
                    node_autodel = 1;
832
0
                }
833
0
                break;
834
0
            }
835
0
        }
836
0
    }
837
838
0
    return node_autodel;
839
0
}
840
841
/**
842
 * @brief Auto-delete leftover default nodes of deleted cases (that have no existing explicit data).
843
 *
844
 * @param[in,out] first First sibling to search in, is updated if needed.
845
 * @param[in,out] node Default data node instance to check.
846
 * @param[in] mod Module of the siblings, NULL for nested siblings.
847
 * @param[in,out] diff Validation diff.
848
 * @return 1 if @p node auto-deleted and updated to its next sibling.
849
 * @return 0 if @p node was not auto-deleted.
850
 */
851
static ly_bool
852
lyd_validate_autodel_case_dflt(struct lyd_node **first, struct lyd_node **node, const struct lys_module *mod,
853
        struct lyd_node **diff)
854
0
{
855
0
    const struct lysc_node *schema;
856
0
    struct lysc_node_choice *choic;
857
0
    struct lyd_node *iter = NULL;
858
0
    const struct lysc_node *slast = NULL;
859
0
    ly_bool node_autodel = 0;
860
861
0
    assert((*node)->flags & LYD_DEFAULT);
862
863
0
    schema = (*node)->schema;
864
865
0
    if (!schema->parent || (schema->parent->nodetype != LYS_CASE)) {
866
        /* the default node is not a descendant of a case */
867
0
        return 0;
868
0
    }
869
870
0
    choic = (struct lysc_node_choice *)schema->parent->parent;
871
0
    assert(choic->nodetype == LYS_CHOICE);
872
873
0
    if (choic->dflt && (choic->dflt == (struct lysc_node_case *)schema->parent)) {
874
        /* data of a default case, keep them */
875
0
        return 0;
876
0
    }
877
878
    /* try to find an explicit node of the case */
879
0
    while ((iter = lys_getnext_data(iter, *first, &slast, schema->parent, NULL))) {
880
0
        if (!(iter->flags & LYD_DEFAULT)) {
881
0
            break;
882
0
        }
883
0
    }
884
885
0
    if (!iter) {
886
        /* there are only default nodes of the case meaning it does not exist and neither should any default nodes
887
         * of the case, remove this one default node */
888
0
        if (lyd_validate_autodel_node_del(first, *node, mod, 0, node, NULL, NULL, diff)) {
889
0
            node_autodel = 1;
890
0
        }
891
0
    }
892
893
0
    return node_autodel;
894
0
}
895
896
/**
897
 * @brief Validate new siblings in choices, recursively for nested choices.
898
 *
899
 * @param[in,out] first First sibling.
900
 * @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
901
 * @param[in] mod Module of the siblings, NULL for nested siblings.
902
 * @param[in] val_opts Validation options.
903
 * @param[in] int_opts Internal parser options.
904
 * @param[in,out] getnext_ht Getnext HT to use, new @p sparent is added to it.
905
 * @param[in,out] diff Validation diff.
906
 * @return LY_ERR value.
907
 */
908
static LY_ERR
909
lyd_validate_choice_r(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
910
        uint32_t val_opts, uint32_t int_opts, struct ly_ht *getnext_ht, struct lyd_node **diff)
911
0
{
912
0
    LY_ERR r, rc = LY_SUCCESS;
913
0
    const struct lysc_node **choices, **snodes;
914
0
    uint32_t i;
915
916
    /* get cached getnext schema nodes */
917
0
    rc = lyd_val_getnext_get(*first ? (*first)->schema : NULL, sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht,
918
0
            &choices, &snodes);
919
0
    LY_CHECK_GOTO(rc, cleanup);
920
921
0
    if (!choices) {
922
0
        goto cleanup;
923
0
    }
924
925
0
    for (i = 0; *first && choices[i]; ++i) {
926
        /* check case duplicites */
927
0
        r = lyd_validate_cases(first, mod, (struct lysc_node_choice *)choices[i], diff);
928
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
929
930
        /* check for nested choice */
931
0
        r = lyd_validate_choice_r(first, choices[i], mod, val_opts, int_opts, getnext_ht, diff);
932
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
933
0
    }
934
935
0
cleanup:
936
0
    return rc;
937
0
}
938
939
LY_ERR
940
lyd_validate_new(struct lyd_node **first, const struct lysc_node *sparent, const struct lys_module *mod,
941
        uint32_t val_opts, uint32_t int_opts, struct ly_ht *getnext_ht, struct lyd_node **diff)
942
0
{
943
0
    LY_ERR r, rc = LY_SUCCESS;
944
0
    struct lyd_node *node;
945
0
    const struct lysc_node *last_dflt_schema = NULL;
946
947
0
    assert(first && (sparent || mod));
948
949
    /* validate choices */
950
0
    r = lyd_validate_choice_r(first, sparent, mod, val_opts, int_opts, getnext_ht, diff);
951
0
    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
952
953
0
    node = *first;
954
0
    while (node) {
955
0
        if (!node->schema || (mod && (lyd_owner_module(node) != mod))) {
956
            /* opaque node or all top-level data from this module checked */
957
0
            break;
958
0
        }
959
960
0
        if (!(node->flags & (LYD_NEW | LYD_DEFAULT))) {
961
            /* check only new and default nodes */
962
0
            node = node->next;
963
0
            continue;
964
0
        }
965
966
0
        if (lyd_val_has_default(node->schema) && (node->schema != last_dflt_schema) && (node->flags & LYD_NEW)) {
967
            /* remove old default(s) of the new node if an explicit instance exists */
968
0
            last_dflt_schema = node->schema;
969
0
            if (node->schema->nodetype == LYS_LEAFLIST) {
970
0
                if (lyd_validate_autodel_leaflist_dflt(first, &node, mod, diff)) {
971
0
                    continue;
972
0
                }
973
0
            } else {
974
0
                if (lyd_validate_autodel_cont_leaf_dflt(first, &node, mod, diff)) {
975
0
                    continue;
976
0
                }
977
0
            }
978
0
        }
979
980
0
        if (node->flags & LYD_NEW) {
981
            /* then check new node instance duplicities */
982
0
            r = lyd_validate_duplicates(*first, node, val_opts);
983
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
984
985
            /* this node is valid */
986
0
            node->flags &= ~LYD_NEW;
987
0
        }
988
989
0
        if (node->flags & LYD_DEFAULT) {
990
            /* remove leftover default nodes from a no-longer existing case */
991
0
            if (lyd_validate_autodel_case_dflt(first, &node, mod, diff)) {
992
0
                continue;
993
0
            }
994
0
        }
995
996
        /* next iter */
997
0
        node = node->next;
998
0
    }
999
1000
0
cleanup:
1001
0
    return rc;
1002
0
}
1003
1004
/**
1005
 * @brief Evaluate any "when" conditions of a non-existent data node with existing parent.
1006
 *
1007
 * @param[in] first First data sibling of the non-existing node.
1008
 * @param[in] parent Data parent of the non-existing node.
1009
 * @param[in] snode Schema node of the non-existing node.
1010
 * @param[in] val_opts Validation options.
1011
 * @param[out] disabled First when that evaluated false, if any.
1012
 * @return LY_ERR value.
1013
 */
1014
static LY_ERR
1015
lyd_validate_dummy_when(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
1016
        uint32_t val_opts, const struct lysc_when **disabled)
1017
0
{
1018
0
    LY_ERR rc = LY_SUCCESS;
1019
0
    struct lyd_node *tree, *dummy = NULL;
1020
0
    uint32_t xp_opts;
1021
1022
    /* find root */
1023
0
    if (parent) {
1024
0
        tree = (struct lyd_node *)parent;
1025
0
        while (tree->parent) {
1026
0
            tree = tree->parent;
1027
0
        }
1028
0
        tree = lyd_first_sibling(tree);
1029
0
    } else {
1030
        /* is the first sibling from the same module, but may not be the actual first */
1031
0
        tree = lyd_first_sibling(first);
1032
0
    }
1033
1034
    /* create dummy opaque node */
1035
0
    rc = lyd_new_opaq((struct lyd_node *)parent, snode->module->ctx, snode->name, NULL, NULL, snode->module->name, &dummy);
1036
0
    LY_CHECK_GOTO(rc, cleanup);
1037
1038
    /* connect it if needed */
1039
0
    if (!parent) {
1040
0
        if (first) {
1041
0
            lyd_insert_sibling((struct lyd_node *)first, dummy, &tree);
1042
0
        } else {
1043
0
            assert(!tree);
1044
0
            tree = dummy;
1045
0
        }
1046
0
    }
1047
1048
    /* explicitly specified accesible tree */
1049
0
    if (snode->flags & LYS_CONFIG_W) {
1050
0
        xp_opts = LYXP_ACCESS_TREE_CONFIG;
1051
0
    } else {
1052
0
        xp_opts = LYXP_ACCESS_TREE_ALL;
1053
0
    }
1054
1055
    /* evaluate all when */
1056
0
    rc = lyd_validate_node_when(tree, dummy, snode, xp_opts, disabled);
1057
0
    if ((rc == LY_EINCOMPLETE) && (val_opts & LYD_VALIDATE_MULTI_ERROR)) {
1058
        /* cannot evaluate properly, just ignore */
1059
0
        rc = LY_SUCCESS;
1060
0
    }
1061
1062
0
    if (rc == LY_EINCOMPLETE) {
1063
        /* all other when must be resolved by now */
1064
0
        LOGINT(snode->module->ctx);
1065
0
        rc = LY_EINT;
1066
0
        goto cleanup;
1067
0
    } else if (rc) {
1068
        /* error */
1069
0
        goto cleanup;
1070
0
    }
1071
1072
0
cleanup:
1073
0
    lyd_free_tree(dummy);
1074
0
    return rc;
1075
0
}
1076
1077
/**
1078
 * @brief Validate mandatory node existence.
1079
 *
1080
 * @param[in] first First sibling to search in.
1081
 * @param[in] parent Data parent.
1082
 * @param[in] snode Schema node to validate.
1083
 * @param[in] val_opts Validation options.
1084
 * @return LY_ERR value.
1085
 */
1086
static LY_ERR
1087
lyd_validate_mandatory(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
1088
        uint32_t val_opts)
1089
0
{
1090
0
    const struct lysc_when *disabled;
1091
1092
0
    if (snode->nodetype == LYS_CHOICE) {
1093
        /* some data of a choice case exist */
1094
0
        if (lys_getnext_data(NULL, first, NULL, snode, NULL)) {
1095
0
            return LY_SUCCESS;
1096
0
        }
1097
0
    } else {
1098
0
        assert(snode->nodetype & (LYS_LEAF | LYS_CONTAINER | LYD_NODE_ANY));
1099
1100
0
        if (!lyd_find_sibling_val(first, snode, NULL, 0, NULL)) {
1101
            /* data instance found */
1102
0
            return LY_SUCCESS;
1103
0
        }
1104
0
    }
1105
1106
0
    disabled = NULL;
1107
0
    if (lysc_has_when(snode)) {
1108
        /* if there are any when conditions, they must be true for a validation error */
1109
0
        LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, val_opts, &disabled));
1110
0
    }
1111
1112
0
    if (!disabled) {
1113
0
        if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1114
            /* only a warning */
1115
0
            if (snode->nodetype == LYS_CHOICE) {
1116
0
                LOGWRN(snode->module->ctx, "Mandatory choice \"%s\" data do not exist.", snode->name);
1117
0
            } else {
1118
0
                LOGWRN(snode->module->ctx, "Mandatory node \"%s\" instance does not exist.", snode->name);
1119
0
            }
1120
0
        } else {
1121
            /* node instance not found */
1122
0
            if (!parent) {
1123
0
                LOG_LOCSET(snode);
1124
0
            }
1125
0
            if (snode->nodetype == LYS_CHOICE) {
1126
0
                LOGVAL_APPTAG(snode->module->ctx, "missing-choice", parent, LY_VCODE_NOMAND_CHOIC, snode->name);
1127
0
            } else {
1128
0
                LOGVAL(snode->module->ctx, parent, LY_VCODE_NOMAND, snode->name);
1129
0
            }
1130
0
            if (!parent) {
1131
0
                LOG_LOCBACK(1);
1132
0
            }
1133
0
            return LY_EVALID;
1134
0
        }
1135
0
    }
1136
1137
0
    return LY_SUCCESS;
1138
0
}
1139
1140
/**
1141
 * @brief Validate min/max-elements constraints, if any.
1142
 *
1143
 * @param[in] first First sibling to search in.
1144
 * @param[in] parent Data parent.
1145
 * @param[in] snode Schema node to validate.
1146
 * @param[in] min Minimum number of elements, 0 for no restriction.
1147
 * @param[in] max Max number of elements, 0 for no restriction.
1148
 * @param[in] val_opts Validation options.
1149
 * @return LY_ERR value.
1150
 */
1151
static LY_ERR
1152
lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode,
1153
        uint32_t min, uint32_t max, uint32_t val_opts)
1154
0
{
1155
0
    LY_ERR rc = LY_SUCCESS;
1156
0
    uint32_t count = 0;
1157
0
    struct lyd_node *iter, *last_iter = NULL;
1158
0
    const struct lysc_when *disabled;
1159
1160
0
    assert(min || max);
1161
1162
0
    LYD_LIST_FOR_INST(first, snode, iter) {
1163
0
        last_iter = iter;
1164
0
        ++count;
1165
1166
0
        if (min && (count == min)) {
1167
            /* satisfied */
1168
0
            min = 0;
1169
0
            if (!max) {
1170
                /* nothing more to check */
1171
0
                break;
1172
0
            }
1173
0
        }
1174
0
        if (max && (count > max)) {
1175
            /* not satisifed */
1176
0
            break;
1177
0
        }
1178
0
    }
1179
1180
0
    if (min) {
1181
0
        assert(count < min);
1182
1183
0
        disabled = NULL;
1184
0
        if (lysc_has_when(snode)) {
1185
            /* if there are any when conditions, they must be true for a validation error */
1186
0
            LY_CHECK_RET(lyd_validate_dummy_when(first, parent, snode, val_opts, &disabled));
1187
0
        }
1188
1189
0
        if (disabled) {
1190
            /* satisfied */
1191
0
            min = 0;
1192
0
        }
1193
0
    }
1194
0
    if (max && (count <= max)) {
1195
        /* satisfied */
1196
0
        max = 0;
1197
0
    }
1198
1199
0
    if (min || max) {
1200
0
        if (min) {
1201
0
            if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1202
                /* only a warning */
1203
0
                LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name);
1204
0
            } else {
1205
0
                if (!last_iter) {
1206
0
                    LOG_LOCSET(snode);
1207
0
                }
1208
0
                LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", last_iter ? last_iter : parent, LY_VCODE_NOMIN,
1209
0
                        snode->name);
1210
0
                if (!last_iter) {
1211
0
                    LOG_LOCBACK(1);
1212
0
                }
1213
0
                rc = LY_EVALID;
1214
0
            }
1215
0
        } else if (max) {
1216
0
            if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1217
                /* only a warning */
1218
0
                LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name);
1219
0
            } else {
1220
0
                if (!last_iter) {
1221
0
                    LOG_LOCSET(snode);
1222
0
                }
1223
0
                LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", last_iter ? last_iter : parent, LY_VCODE_NOMAX,
1224
0
                        snode->name);
1225
0
                if (!last_iter) {
1226
0
                    LOG_LOCBACK(1);
1227
0
                }
1228
0
                rc = LY_EVALID;
1229
0
            }
1230
0
        }
1231
0
    }
1232
1233
0
    return rc;
1234
0
}
1235
1236
/**
1237
 * @brief Find node referenced by a list unique statement.
1238
 *
1239
 * @param[in] uniq_leaf Unique leaf to find.
1240
 * @param[in] list List instance to use for the search.
1241
 * @return Found leaf,
1242
 * @return NULL if no leaf found.
1243
 */
1244
static struct lyd_node *
1245
lyd_val_uniq_find_leaf(const struct lysc_node_leaf *uniq_leaf, const struct lyd_node *list)
1246
0
{
1247
0
    struct lyd_node *node;
1248
0
    const struct lysc_node *iter;
1249
0
    size_t depth = 0, i;
1250
1251
    /* get leaf depth */
1252
0
    for (iter = &uniq_leaf->node; iter && (iter != list->schema); iter = lysc_data_parent(iter)) {
1253
0
        ++depth;
1254
0
    }
1255
1256
0
    node = (struct lyd_node *)list;
1257
0
    while (node && depth) {
1258
        /* find schema node with this depth */
1259
0
        for (i = depth - 1, iter = &uniq_leaf->node; i; iter = lysc_data_parent(iter)) {
1260
0
            --i;
1261
0
        }
1262
1263
        /* find iter instance in children */
1264
0
        assert(iter->nodetype & (LYS_CONTAINER | LYS_LEAF));
1265
0
        lyd_find_sibling_val(lyd_child(node), iter, NULL, 0, &node);
1266
0
        --depth;
1267
0
    }
1268
1269
0
    return node;
1270
0
}
1271
1272
/**
1273
 * @brief Unique list validation callback argument.
1274
 */
1275
struct lyd_val_uniq_arg {
1276
    LY_ARRAY_COUNT_TYPE action; /**< Action to perform - 0 to compare all uniques, n to compare only n-th unique. */
1277
    uint32_t val_opts;          /**< Validation options. */
1278
};
1279
1280
/**
1281
 * @brief Callback for comparing 2 list unique leaf values.
1282
 *
1283
 * Implementation of ::lyht_value_equal_cb.
1284
 */
1285
static ly_bool
1286
lyd_val_uniq_list_equal(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *cb_data)
1287
0
{
1288
0
    const struct ly_ctx *ctx;
1289
0
    struct lysc_node_list *slist;
1290
0
    struct lyd_node *diter, *first, *second;
1291
0
    const char *val1, *val2, *canon1, *canon2;
1292
0
    char *path1, *path2, *uniq_str, *ptr;
1293
0
    LY_ARRAY_COUNT_TYPE u, v;
1294
0
    struct lyd_val_uniq_arg *arg = cb_data;
1295
0
    const uint32_t uniq_err_msg_size = 1024;
1296
1297
0
    assert(val1_p && val2_p);
1298
1299
0
    first = *((struct lyd_node **)val1_p);
1300
0
    second = *((struct lyd_node **)val2_p);
1301
1302
0
    assert(first && (first->schema->nodetype == LYS_LIST));
1303
0
    assert(second && (second->schema == first->schema));
1304
1305
0
    ctx = LYD_CTX(first);
1306
1307
0
    slist = (struct lysc_node_list *)first->schema;
1308
1309
    /* compare unique leaves */
1310
0
    if (arg->action > 0) {
1311
0
        u = arg->action - 1;
1312
0
        if (u < LY_ARRAY_COUNT(slist->uniques)) {
1313
0
            goto uniquecheck;
1314
0
        }
1315
0
    }
1316
0
    LY_ARRAY_FOR(slist->uniques, u) {
1317
0
uniquecheck:
1318
0
        LY_ARRAY_FOR(slist->uniques[u], v) {
1319
            /* first */
1320
0
            canon1 = NULL;
1321
0
            val1 = NULL;
1322
0
            diter = lyd_val_uniq_find_leaf(slist->uniques[u][v], first);
1323
0
            if (diter) {
1324
0
                val1 = lyd_get_value(diter);
1325
0
            } else if (slist->uniques[u][v]->dflt.str) {
1326
                /* use canonical default value */
1327
0
                lyd_value_validate3(first->schema, slist->uniques[u][v]->dflt.str, strlen(slist->uniques[u][v]->dflt.str),
1328
0
                        LY_VALUE_SCHEMA_RESOLVED, slist->uniques[u][v]->dflt.prefixes, LYD_HINT_SCHEMA, NULL, 1,
1329
0
                        NULL, &canon2);
1330
0
                val1 = canon1;
1331
0
            }
1332
1333
            /* second */
1334
0
            canon2 = NULL;
1335
0
            val2 = NULL;
1336
0
            diter = lyd_val_uniq_find_leaf(slist->uniques[u][v], second);
1337
0
            if (diter) {
1338
0
                val2 = lyd_get_value(diter);
1339
0
            } else if (slist->uniques[u][v]->dflt.str) {
1340
                /* use canonical default value */
1341
0
                lyd_value_validate3(first->schema, slist->uniques[u][v]->dflt.str, strlen(slist->uniques[u][v]->dflt.str),
1342
0
                        LY_VALUE_SCHEMA_RESOLVED, slist->uniques[u][v]->dflt.prefixes, LYD_HINT_SCHEMA, NULL, 1,
1343
0
                        NULL, &canon2);
1344
0
                val2 = canon2;
1345
0
            }
1346
1347
0
            lydict_remove(ctx, canon1);
1348
0
            lydict_remove(ctx, canon2);
1349
0
            if (!val1 || !val2 || (val1 != val2)) {
1350
                /* values differ or either one is not set */
1351
0
                break;
1352
0
            }
1353
0
        }
1354
0
        if (v && (v == LY_ARRAY_COUNT(slist->uniques[u]))) {
1355
            /* all unique leaves are the same in this set, create this nice error */
1356
0
            path1 = lyd_path(first, LYD_PATH_STD, NULL, 0);
1357
0
            path2 = lyd_path(second, LYD_PATH_STD, NULL, 0);
1358
1359
            /* use buffer to rebuild the unique string */
1360
0
            uniq_str = malloc(uniq_err_msg_size);
1361
0
            uniq_str[0] = '\0';
1362
0
            ptr = uniq_str;
1363
0
            LY_ARRAY_FOR(slist->uniques[u], v) {
1364
0
                if (v) {
1365
0
                    strcpy(ptr, " ");
1366
0
                    ++ptr;
1367
0
                }
1368
0
                ptr = lysc_path_until((struct lysc_node *)slist->uniques[u][v], &slist->node, LYSC_PATH_LOG,
1369
0
                        ptr, uniq_err_msg_size - (ptr - uniq_str));
1370
0
                if (!ptr) {
1371
                    /* path will be incomplete, whatever */
1372
0
                    break;
1373
0
                }
1374
1375
0
                ptr += strlen(ptr);
1376
0
            }
1377
0
            if (arg->val_opts & LYD_VALIDATE_OPERATIONAL) {
1378
                /* only a warning */
1379
0
                LOGWRN(ctx, "Unique data leaf(s) \"%s\" not satisfied in \"%s\" and \"%s\".", uniq_str, path1, path2);
1380
0
            } else {
1381
0
                LOGVAL_APPTAG(ctx, "data-not-unique", second, LY_VCODE_NOUNIQ, uniq_str, path1, path2);
1382
0
            }
1383
1384
0
            free(path1);
1385
0
            free(path2);
1386
0
            free(uniq_str);
1387
1388
0
            if (!(arg->val_opts & LYD_VALIDATE_OPERATIONAL)) {
1389
0
                return 1;
1390
0
            }
1391
0
        }
1392
1393
0
        if (arg->action > 0) {
1394
            /* done */
1395
0
            return 0;
1396
0
        }
1397
0
    }
1398
1399
0
    return 0;
1400
0
}
1401
1402
/**
1403
 * @brief Validate list unique leaves.
1404
 *
1405
 * @param[in] first First sibling to search in.
1406
 * @param[in] snode Schema node to validate.
1407
 * @param[in] uniques List unique arrays to validate.
1408
 * @param[in] val_opts Validation options.
1409
 * @return LY_ERR value.
1410
 */
1411
static LY_ERR
1412
lyd_validate_unique(const struct lyd_node *first, const struct lysc_node *snode, const struct lysc_node_leaf ***uniques,
1413
        uint32_t val_opts)
1414
0
{
1415
0
    const struct lyd_node *diter;
1416
0
    struct ly_set *set;
1417
0
    LY_ARRAY_COUNT_TYPE u, v, x = 0;
1418
0
    LY_ERR ret = LY_SUCCESS;
1419
0
    uint32_t hash, i;
1420
0
    struct lyd_val_uniq_arg arg, *args = NULL;
1421
0
    struct ly_ht **uniqtables = NULL;
1422
0
    const char *val;
1423
0
    struct ly_ctx *ctx = snode->module->ctx;
1424
1425
0
    assert(uniques);
1426
1427
    /* get all list instances */
1428
0
    LY_CHECK_RET(ly_set_new(&set));
1429
0
    LY_LIST_FOR(first, diter) {
1430
0
        if (diter->schema == snode) {
1431
0
            ret = ly_set_add(set, (void *)diter, 1, NULL);
1432
0
            LY_CHECK_GOTO(ret, cleanup);
1433
0
        }
1434
0
    }
1435
1436
0
    if (set->count == 2) {
1437
        /* simple comparison */
1438
0
        arg.action = 0;
1439
0
        arg.val_opts = val_opts;
1440
0
        if (lyd_val_uniq_list_equal(&set->objs[0], &set->objs[1], 0, &arg)) {
1441
            /* instance duplication */
1442
0
            ret = LY_EVALID;
1443
0
            goto cleanup;
1444
0
        }
1445
0
    } else if (set->count > 2) {
1446
        /* use hashes for comparison */
1447
0
        uniqtables = malloc(LY_ARRAY_COUNT(uniques) * sizeof *uniqtables);
1448
0
        args = malloc(LY_ARRAY_COUNT(uniques) * sizeof *args);
1449
0
        LY_CHECK_ERR_GOTO(!uniqtables || !args, LOGMEM(ctx); ret = LY_EMEM, cleanup);
1450
0
        x = LY_ARRAY_COUNT(uniques);
1451
0
        for (v = 0; v < x; v++) {
1452
0
            args[v].action = v + 1;
1453
0
            args[v].val_opts = val_opts;
1454
0
            uniqtables[v] = lyht_new(lyht_get_fixed_size(set->count), sizeof(struct lyd_node *),
1455
0
                    lyd_val_uniq_list_equal, &args[v], 0);
1456
0
            LY_CHECK_ERR_GOTO(!uniqtables[v], LOGMEM(ctx); ret = LY_EMEM, cleanup);
1457
0
        }
1458
1459
0
        for (i = 0; i < set->count; i++) {
1460
            /* loop for unique - get the hash for the instances */
1461
0
            for (u = 0; u < x; u++) {
1462
0
                val = NULL;
1463
0
                for (v = hash = 0; v < LY_ARRAY_COUNT(uniques[u]); v++) {
1464
0
                    diter = lyd_val_uniq_find_leaf(uniques[u][v], set->objs[i]);
1465
0
                    if (diter) {
1466
0
                        val = lyd_get_value(diter);
1467
0
                    } else if (uniques[u][v]->dflt.str) {
1468
                        /* use canonical default value */
1469
0
                        ret = lyd_value_validate3(snode, uniques[u][v]->dflt.str, strlen(uniques[u][v]->dflt.str),
1470
0
                                LY_VALUE_SCHEMA_RESOLVED, uniques[u][v]->dflt.prefixes, LYD_HINT_SCHEMA, NULL, 1,
1471
0
                                NULL, &val);
1472
0
                        LY_CHECK_GOTO(ret, cleanup);
1473
0
                    }
1474
0
                    if (!val) {
1475
                        /* unique item not present nor has default value */
1476
0
                        break;
1477
0
                    }
1478
1479
                    /* get hash key */
1480
0
                    hash = lyht_hash_multi(hash, val, strlen(val));
1481
0
                }
1482
0
                if (!val) {
1483
                    /* skip this list instance since its unique set is incomplete */
1484
0
                    continue;
1485
0
                }
1486
1487
                /* finish the hash value */
1488
0
                hash = lyht_hash_multi(hash, NULL, 0);
1489
1490
                /* insert into the hashtable */
1491
0
                ret = lyht_insert(uniqtables[u], &set->objs[i], hash, NULL);
1492
0
                if (ret == LY_EEXIST) {
1493
                    /* instance duplication */
1494
0
                    ret = LY_EVALID;
1495
0
                }
1496
0
                LY_CHECK_GOTO(ret != LY_SUCCESS, cleanup);
1497
0
            }
1498
0
        }
1499
0
    }
1500
1501
0
cleanup:
1502
0
    ly_set_free(set, NULL);
1503
0
    for (v = 0; v < x; v++) {
1504
0
        if (!uniqtables[v]) {
1505
            /* failed when allocating uniquetables[j], following j are not allocated */
1506
0
            break;
1507
0
        }
1508
0
        lyht_free(uniqtables[v], NULL);
1509
0
    }
1510
0
    free(uniqtables);
1511
0
    free(args);
1512
1513
0
    return ret;
1514
0
}
1515
1516
/**
1517
 * @brief Validate data siblings based on generic schema node restrictions, recursively for schema-only nodes.
1518
 *
1519
 * @param[in] first First sibling to search in.
1520
 * @param[in] parent Data parent.
1521
 * @param[in] sparent Schema parent of the nodes to check.
1522
 * @param[in] mod Module of the nodes to check.
1523
 * @param[in] val_opts Validation options, see @ref datavalidationoptions.
1524
 * @param[in] int_opts Internal parser options.
1525
 * @param[in,out] getnext_ht Getnext HT to use, new @p sparent is added to it.
1526
 * @return LY_ERR value.
1527
 */
1528
static LY_ERR
1529
lyd_validate_siblings_schema_r(const struct lyd_node *first, const struct lyd_node *parent,
1530
        const struct lysc_node *sparent, const struct lys_module *mod, uint32_t val_opts, uint32_t int_opts,
1531
        struct ly_ht *getnext_ht)
1532
0
{
1533
0
    LY_ERR r, rc = LY_SUCCESS;
1534
0
    const struct lysc_node *snode, *scase, **choices, **snodes;
1535
0
    struct lysc_node_list *slist;
1536
0
    struct lysc_node_leaflist *sllist;
1537
0
    uint32_t i;
1538
1539
    /* get cached getnext schema nodes */
1540
0
    rc = lyd_val_getnext_get(first ? first->schema : NULL, sparent, mod, int_opts & LYD_INTOPT_REPLY, getnext_ht,
1541
0
            &choices, &snodes);
1542
0
    LY_CHECK_GOTO(rc, cleanup);
1543
1544
0
    for (i = 0; choices && choices[i]; ++i) {
1545
0
        snode = choices[i];
1546
1547
0
        if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
1548
            /* skip state nodes */
1549
0
            continue;
1550
0
        }
1551
1552
0
        if (snode->flags & LYS_MAND_TRUE) {
1553
            /* check generic mandatory existence */
1554
0
            r = lyd_validate_mandatory(first, parent, snode, val_opts);
1555
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1556
0
        }
1557
1558
        /* find the existing case, if any */
1559
0
        LY_LIST_FOR(lysc_node_child(snode), scase) {
1560
0
            if (lys_getnext_data(NULL, first, NULL, scase, NULL)) {
1561
                /* validate only this case */
1562
0
                r = lyd_validate_siblings_schema_r(first, parent, scase, mod, val_opts, int_opts, getnext_ht);
1563
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1564
0
                break;
1565
0
            }
1566
0
        }
1567
0
    }
1568
1569
0
    for (i = 0; snodes && snodes[i]; ++i) {
1570
0
        snode = snodes[i];
1571
1572
0
        if ((val_opts & LYD_VALIDATE_NO_STATE) && (snode->flags & LYS_CONFIG_R)) {
1573
            /* skip state nodes */
1574
0
            continue;
1575
0
        }
1576
1577
        /* check min-elements and max-elements */
1578
0
        if (snode->nodetype == LYS_LIST) {
1579
0
            slist = (struct lysc_node_list *)snode;
1580
0
            if (slist->min || (slist->max < UINT32_MAX)) {
1581
0
                r = lyd_validate_minmax(first, parent, snode, slist->min, slist->max, val_opts);
1582
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1583
0
            }
1584
1585
            /* check unique */
1586
0
            if (slist->uniques) {
1587
0
                r = lyd_validate_unique(first, snode, (const struct lysc_node_leaf ***)slist->uniques, val_opts);
1588
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1589
0
            }
1590
0
        } else if (snode->nodetype == LYS_LEAFLIST) {
1591
0
            sllist = (struct lysc_node_leaflist *)snode;
1592
0
            if (sllist->min || (sllist->max < UINT32_MAX)) {
1593
0
                r = lyd_validate_minmax(first, parent, snode, sllist->min, sllist->max, val_opts);
1594
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1595
0
            }
1596
1597
0
        } else if (snode->flags & LYS_MAND_TRUE) {
1598
            /* check generic mandatory existence */
1599
0
            r = lyd_validate_mandatory(first, parent, snode, val_opts);
1600
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1601
0
        }
1602
0
    }
1603
1604
0
cleanup:
1605
0
    return rc;
1606
0
}
1607
1608
/**
1609
 * @brief Validate obsolete nodes, only warnings are printed.
1610
 *
1611
 * @param[in] node Node to check.
1612
 */
1613
static void
1614
lyd_validate_obsolete(const struct lyd_node *node)
1615
0
{
1616
0
    const struct lysc_node *snode;
1617
1618
0
    snode = node->schema;
1619
0
    do {
1620
0
        if (snode->flags & LYS_STATUS_OBSLT && (!(snode->nodetype & LYD_NODE_INNER) || lyd_child(node))) {
1621
0
            LOGWRN(snode->module->ctx, "Obsolete schema node \"%s\" instantiated in data.", snode->name);
1622
0
            break;
1623
0
        }
1624
1625
0
        snode = snode->parent;
1626
0
    } while (snode && (snode->nodetype & (LYS_CHOICE | LYS_CASE)));
1627
0
}
1628
1629
/**
1630
 * @brief Validate must conditions of a data node.
1631
 *
1632
 * @param[in] node Node to validate.
1633
 * @param[in] val_opts Validation options.
1634
 * @param[in] int_opts Internal parser options.
1635
 * @param[in] xpath_opts Additional XPath options to use.
1636
 * @return LY_ERR value.
1637
 */
1638
static LY_ERR
1639
lyd_validate_must(const struct lyd_node *node, uint32_t val_opts, uint32_t int_opts, uint32_t xpath_opts)
1640
0
{
1641
0
    LY_ERR r, rc = LY_SUCCESS;
1642
0
    struct lyxp_set xp_set;
1643
0
    struct lysc_must *musts;
1644
0
    const struct lyd_node *tree;
1645
0
    const struct lysc_node *schema;
1646
0
    const char *emsg, *eapptag;
1647
0
    LY_ARRAY_COUNT_TYPE u;
1648
1649
0
    assert((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) != (LYD_INTOPT_RPC | LYD_INTOPT_REPLY));
1650
0
    assert((int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) != (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY));
1651
1652
0
    if (node->schema->nodetype & (LYS_ACTION | LYS_RPC)) {
1653
0
        if (int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION)) {
1654
0
            schema = &((struct lysc_node_action *)node->schema)->input.node;
1655
0
        } else if (int_opts & LYD_INTOPT_REPLY) {
1656
0
            schema = &((struct lysc_node_action *)node->schema)->output.node;
1657
0
        } else {
1658
0
            LOGINT_RET(LYD_CTX(node));
1659
0
        }
1660
0
    } else {
1661
0
        schema = node->schema;
1662
0
    }
1663
0
    musts = lysc_node_musts(schema);
1664
0
    if (!musts) {
1665
        /* no must to evaluate */
1666
0
        return LY_SUCCESS;
1667
0
    }
1668
1669
    /* find first top-level node */
1670
0
    for (tree = node; tree->parent; tree = tree->parent) {}
1671
0
    tree = lyd_first_sibling(tree);
1672
1673
0
    LY_ARRAY_FOR(musts, u) {
1674
0
        memset(&xp_set, 0, sizeof xp_set);
1675
1676
        /* evaluate must */
1677
0
        r = lyxp_eval(LYD_CTX(node), musts[u].cond, node->schema->module, LY_VALUE_SCHEMA_RESOLVED,
1678
0
                musts[u].prefixes, node, node, tree, NULL, &xp_set, LYXP_SCHEMA | xpath_opts);
1679
0
        if (r == LY_EINCOMPLETE) {
1680
0
            LOGERR(LYD_CTX(node), LY_EINCOMPLETE,
1681
0
                    "Must \"%s\" depends on a node with a when condition, which has not been evaluated.", musts[u].cond->expr);
1682
0
        }
1683
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1684
1685
        /* check the result */
1686
0
        lyxp_set_cast(&xp_set, LYXP_SET_BOOLEAN);
1687
0
        if (!xp_set.val.bln) {
1688
0
            if (val_opts & LYD_VALIDATE_OPERATIONAL) {
1689
                /* only a warning */
1690
0
                emsg = musts[u].emsg;
1691
0
                if (emsg) {
1692
0
                    LOGWRN(LYD_CTX(node), "%s", emsg);
1693
0
                } else {
1694
0
                    LOGWRN(LYD_CTX(node), "Must condition \"%s\" not satisfied.", musts[u].cond->expr);
1695
0
                }
1696
0
            } else {
1697
                /* use specific error information */
1698
0
                emsg = musts[u].emsg;
1699
0
                eapptag = musts[u].eapptag ? musts[u].eapptag : "must-violation";
1700
0
                if (emsg) {
1701
0
                    LOGVAL_APPTAG(LYD_CTX(node), eapptag, node, LYVE_DATA, "%s", emsg);
1702
0
                } else {
1703
0
                    LOGVAL_APPTAG(LYD_CTX(node), eapptag, node, LY_VCODE_NOMUST, musts[u].cond->expr);
1704
0
                }
1705
0
                r = LY_EVALID;
1706
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1707
0
            }
1708
0
        }
1709
0
    }
1710
1711
0
cleanup:
1712
0
    return rc;
1713
0
}
1714
1715
/**
1716
 * @brief Perform all remaining validation tasks, the data tree must be final when calling this function.
1717
 *
1718
 * @param[in] first First sibling.
1719
 * @param[in] parent Data parent.
1720
 * @param[in] sparent Schema parent of the siblings, NULL for top-level siblings.
1721
 * @param[in] mod Module of the siblings, NULL for nested siblings.
1722
 * @param[in] ext Extension instance to use, if relevant.
1723
 * @param[in] val_opts Validation options (@ref datavalidationoptions).
1724
 * @param[in] int_opts Internal parser options.
1725
 * @param[in] must_xp_opts Additional XPath options to use for evaluating "must".
1726
 * @param[in,out] getnext_ht Getnext HT to use.
1727
 * @return LY_ERR value.
1728
 */
1729
static LY_ERR
1730
lyd_validate_final_r(struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *sparent,
1731
        const struct lys_module *mod, const struct lysc_ext_instance *ext, uint32_t val_opts, uint32_t int_opts,
1732
        uint32_t must_xp_opts, struct ly_ht *getnext_ht)
1733
0
{
1734
0
    LY_ERR r, rc = LY_SUCCESS;
1735
0
    const char *innode;
1736
0
    struct lyd_node *node;
1737
1738
    /* validate all restrictions of nodes themselves */
1739
0
    LY_LIST_FOR(first, node) {
1740
0
        if ((node->flags & LYD_EXT) && !ext) {
1741
            /* ext instance data should have already been validated */
1742
0
            continue;
1743
0
        }
1744
1745
        /* opaque data */
1746
0
        if (!node->schema) {
1747
0
            r = lyd_parse_opaq_error(node);
1748
0
            goto next_iter;
1749
0
        }
1750
1751
0
        if (!node->parent && mod && (lyd_owner_module(node) != mod)) {
1752
            /* all top-level data from this module checked */
1753
0
            break;
1754
0
        }
1755
1756
        /* no state/input/output/op data */
1757
0
        innode = NULL;
1758
0
        if ((val_opts & LYD_VALIDATE_NO_STATE) && (node->schema->flags & LYS_CONFIG_R)) {
1759
0
            innode = "state";
1760
0
        } else if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION)) && (node->schema->flags & LYS_IS_OUTPUT)) {
1761
0
            innode = "output";
1762
0
        } else if ((int_opts & LYD_INTOPT_REPLY) && (node->schema->flags & LYS_IS_INPUT)) {
1763
0
            innode = "input";
1764
0
        } else if (!(int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_RPC)) {
1765
0
            innode = "rpc";
1766
0
        } else if (!(int_opts & (LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) && (node->schema->nodetype == LYS_ACTION)) {
1767
0
            innode = "action";
1768
0
        } else if (!(int_opts & LYD_INTOPT_NOTIF) && (node->schema->nodetype == LYS_NOTIF)) {
1769
0
            innode = "notification";
1770
0
        }
1771
0
        if (innode) {
1772
0
            LOGVAL(LYD_CTX(node), node, LY_VCODE_UNEXPNODE, innode, node->schema->name);
1773
0
            r = LY_EVALID;
1774
0
            goto next_iter;
1775
0
        }
1776
1777
        /* obsolete data */
1778
0
        lyd_validate_obsolete(node);
1779
1780
        /* node's musts */
1781
0
        if ((r = lyd_validate_must(node, val_opts, int_opts & ~LYD_INTOPT_SKIP_SIBLINGS, must_xp_opts))) {
1782
0
            goto next_iter;
1783
0
        }
1784
1785
        /* node value was checked by plugins */
1786
1787
0
next_iter:
1788
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1789
1790
0
        if (int_opts & LYD_INTOPT_SKIP_SIBLINGS) {
1791
0
            break;
1792
0
        }
1793
0
    }
1794
1795
    /* validate schema-based restrictions */
1796
0
    r = lyd_validate_siblings_schema_r(first, parent, sparent, mod, val_opts, int_opts & ~LYD_INTOPT_SKIP_SIBLINGS,
1797
0
            getnext_ht);
1798
0
    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1799
1800
0
    LY_LIST_FOR(first, node) {
1801
0
        if ((node->flags & LYD_EXT) || !node->schema || (!node->parent && mod && (lyd_owner_module(node) != mod))) {
1802
            /* condensed condition of the previous loop */
1803
0
            break;
1804
0
        }
1805
1806
        /* validate all children recursively */
1807
0
        r = lyd_validate_final_r(lyd_child(node), node, node->schema, NULL, ext, val_opts,
1808
0
                int_opts & ~LYD_INTOPT_SKIP_SIBLINGS, must_xp_opts, getnext_ht);
1809
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1810
1811
        /* set default for containers */
1812
0
        lyd_np_cont_dflt_set(node);
1813
1814
0
        if (int_opts & LYD_INTOPT_SKIP_SIBLINGS) {
1815
0
            break;
1816
0
        }
1817
0
    }
1818
1819
0
cleanup:
1820
0
    return rc;
1821
0
}
1822
1823
/**
1824
 * @brief Store a node with ext instance validation callback to be validated later.
1825
 *
1826
 * @param[in] node Node to store.
1827
 * @param[in] ext Relevant extension instance.
1828
 * @param[in,out] ext_val Set with the nodes to validate.
1829
 * @return LY_ERR value.
1830
 */
1831
static LY_ERR
1832
lyd_validate_ext_add(struct lyd_node *node, const struct lysc_ext_instance *ext, struct ly_set *ext_val)
1833
0
{
1834
0
    struct lyd_ctx_ext_val *ext_v;
1835
1836
    /* store for validation */
1837
0
    ext_v = malloc(sizeof *ext_v);
1838
0
    LY_CHECK_ERR_RET(!ext_v, LOGMEM(LYD_CTX(node)), LY_EMEM);
1839
0
    ext_v->ext = (struct lysc_ext_instance *)ext;
1840
0
    ext_v->sibling = node;
1841
0
    LY_CHECK_RET(ly_set_add(ext_val, ext_v, 1, NULL));
1842
1843
0
    return LY_SUCCESS;
1844
0
}
1845
1846
LY_ERR
1847
lyd_validate_tree_ext(struct lyd_node *node, const struct lysc_ext_instance *ext, struct ly_set *ext_val)
1848
0
{
1849
0
    struct lysc_ext_instance *exts;
1850
0
    struct lyplg_ext *plg_ext;
1851
0
    LY_ARRAY_COUNT_TYPE u;
1852
1853
0
    assert(node->flags & LYD_EXT);
1854
1855
0
    if (ext) {
1856
        /* we have the ext instance already */
1857
0
        plg_ext = LYSC_GET_EXT_PLG(ext->def->plugin_ref);
1858
0
        if (!plg_ext || !plg_ext->validate) {
1859
0
            LOGINT_RET(LYD_CTX(node));
1860
0
        }
1861
1862
        /* store for validation */
1863
0
        LY_CHECK_RET(lyd_validate_ext_add(node, ext, ext_val));
1864
0
    } else {
1865
        /* we must try to validate using all the matching callbacks, they have to decide whether they should validate
1866
         * the data or not */
1867
0
        if (node->parent && node->parent->schema) {
1868
            /* try to find the nested parent extension instance */
1869
0
            exts = node->parent->schema->exts;
1870
0
            LY_ARRAY_FOR(exts, u) {
1871
0
                plg_ext = LYSC_GET_EXT_PLG(exts[u].def->plugin_ref);
1872
0
                if (plg_ext && plg_ext->validate) {
1873
0
                    LY_CHECK_RET(lyd_validate_ext_add(node, &exts[u], ext_val));
1874
0
                }
1875
0
            }
1876
0
        }
1877
1878
0
        if (node->schema) {
1879
            /* try to find a global extension instance */
1880
0
            exts = node->schema->module->compiled->exts;
1881
0
            LY_ARRAY_FOR(exts, u) {
1882
0
                plg_ext = LYSC_GET_EXT_PLG(exts[u].def->plugin_ref);
1883
0
                if (plg_ext && plg_ext->validate) {
1884
0
                    LY_CHECK_RET(lyd_validate_ext_add(node, &exts[u], ext_val));
1885
0
                }
1886
0
            }
1887
0
        }
1888
0
    }
1889
1890
0
    return LY_SUCCESS;
1891
0
}
1892
1893
LY_ERR
1894
lyd_validate_node_ext(struct lyd_node *node, struct ly_set *ext_val)
1895
0
{
1896
0
    struct lysc_ext_instance *exts;
1897
0
    struct lyplg_ext *plg_ext;
1898
0
    LY_ARRAY_COUNT_TYPE u;
1899
1900
    /* try to find a relevant extension instance with validation callback in the schema node ... */
1901
0
    exts = node->schema->exts;
1902
0
    LY_ARRAY_FOR(exts, u) {
1903
0
        plg_ext = LYSC_GET_EXT_PLG(exts[u].def->plugin_ref);
1904
0
        if (plg_ext && plg_ext->validate) {
1905
            /* store for validation */
1906
0
            LY_CHECK_RET(lyd_validate_ext_add(node, &exts[u], ext_val));
1907
0
        }
1908
0
    }
1909
1910
    /* ... and in the type */
1911
0
    if (node->schema->nodetype & LYD_NODE_TERM) {
1912
0
        exts = ((struct lysc_node_leaf *)node->schema)->type->exts;
1913
0
        LY_ARRAY_FOR(exts, u) {
1914
0
            plg_ext = LYSC_GET_EXT_PLG(exts[u].def->plugin_ref);
1915
0
            if (plg_ext && plg_ext->validate) {
1916
                /* store for validation */
1917
0
                LY_CHECK_RET(lyd_validate_ext_add(node, &exts[u], ext_val));
1918
0
            }
1919
0
        }
1920
0
    }
1921
1922
0
    return LY_SUCCESS;
1923
0
}
1924
1925
/**
1926
 * @brief Validate the whole data subtree.
1927
 *
1928
 * @param[in] root Subtree root.
1929
 * @param[in] ext Extension instance whose data to validate.
1930
 * @param[in,out] node_when Set for nodes with when conditions.
1931
 * @param[in,out] node_types Set for unres node types.
1932
 * @param[in,out] meta_types Set for unres metadata types.
1933
 * @param[in,out] ext_val Set for parsed extension data to validate.
1934
 * @param[in] val_opts Validation options.
1935
 * @param[in] int_opts Internal parser options.
1936
 * @param[in,out] getnext_ht Getnext HT to use.
1937
 * @param[in,out] diff Validation diff.
1938
 * @return LY_ERR value.
1939
 */
1940
static LY_ERR
1941
lyd_validate_tree(struct lyd_node *root, const struct lysc_ext_instance *ext, struct ly_set *node_when,
1942
        struct ly_set *node_types, struct ly_set *meta_types, struct ly_set *ext_val, uint32_t val_opts,
1943
        uint32_t int_opts, struct ly_ht *getnext_ht, struct lyd_node **diff)
1944
0
{
1945
0
    LY_ERR r, rc = LY_SUCCESS;
1946
0
    const struct lyd_meta *meta;
1947
0
    const struct lysc_type *type;
1948
0
    struct ly_err_item *err = NULL;
1949
0
    struct lyplg_type *plg_type;
1950
0
    struct lyd_node *node;
1951
0
    uint32_t impl_opts;
1952
1953
0
    LYD_TREE_DFS_BEGIN(root, node) {
1954
0
        if ((node->flags & LYD_EXT) && !ext) {
1955
            /* validate using the extension instance callback */
1956
0
            return lyd_validate_tree_ext(node, NULL, ext_val);
1957
0
        }
1958
1959
0
        if (!node->schema) {
1960
            /* do not validate opaque nodes */
1961
0
            goto next_node;
1962
0
        }
1963
1964
0
        LY_LIST_FOR(node->meta, meta) {
1965
0
            lyplg_ext_get_storage(meta->annotation, LY_STMT_TYPE, sizeof type, (const void **)&type);
1966
0
            if (LYSC_GET_TYPE_PLG(type->plugin_ref)->validate_tree) {
1967
                /* metadata type resolution */
1968
0
                r = ly_set_add(meta_types, (void *)meta, 1, NULL);
1969
0
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1970
0
            }
1971
0
        }
1972
1973
0
        if (node->schema->nodetype & LYD_NODE_TERM) {
1974
0
            plg_type = LYSC_GET_TYPE_PLG(((struct lysc_node_leaf *)node->schema)->type->plugin_ref);
1975
0
            if (plg_type->validate_value) {
1976
                /* value validation */
1977
0
                r = plg_type->validate_value(LYD_CTX(node), ((struct lysc_node_leaf *)node->schema)->type,
1978
0
                        &((struct lyd_node_term *)node)->value, &err);
1979
0
                if (err) {
1980
0
                    ly_err_print(LYD_CTX(node), err, node, NULL);
1981
0
                    ly_err_free(err);
1982
0
                }
1983
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1984
0
            }
1985
1986
0
            if (plg_type->validate_tree) {
1987
                /* node type resolution (tree validation) */
1988
0
                r = ly_set_add(node_types, (void *)node, 1, NULL);
1989
0
                LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1990
0
            }
1991
0
        } else if (node->schema->nodetype & LYD_NODE_INNER) {
1992
            /* new node validation, autodelete */
1993
0
            r = lyd_validate_new(lyd_node_child_p(node), node->schema, NULL, val_opts, int_opts, getnext_ht, diff);
1994
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
1995
1996
            /* add nested defaults */
1997
0
            impl_opts = 0;
1998
0
            if (val_opts & LYD_VALIDATE_NO_STATE) {
1999
0
                impl_opts |= LYD_IMPLICIT_NO_STATE;
2000
0
            }
2001
0
            if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
2002
0
                impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
2003
0
            }
2004
0
            r = lyd_new_implicit(node, lyd_node_child_p(node), NULL, NULL, NULL, NULL, NULL, impl_opts, getnext_ht, diff);
2005
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2006
0
        }
2007
2008
0
        if (lysc_has_when(node->schema)) {
2009
            /* when evaluation */
2010
0
            r = ly_set_add(node_when, (void *)node, 1, NULL);
2011
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2012
0
        }
2013
2014
        /* store for ext instance node validation, if needed */
2015
0
        r = lyd_validate_node_ext(node, ext_val);
2016
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2017
2018
0
next_node:
2019
0
        LYD_TREE_DFS_END(root, node);
2020
0
    }
2021
2022
0
cleanup:
2023
0
    return rc;
2024
0
}
2025
2026
LY_ERR
2027
lyd_validate(struct lyd_node **tree, const struct lys_module *module, const struct ly_ctx *ctx, uint32_t val_opts,
2028
        ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p, struct ly_set *meta_types_p,
2029
        struct ly_set *ext_val_p, struct lyd_node **diff)
2030
0
{
2031
0
    LY_ERR r, rc = LY_SUCCESS;
2032
0
    struct lyd_node *first, *next, **first2, *iter;
2033
0
    const struct lys_module *mod;
2034
0
    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0}, mod_set = {0}, getnext_ht_set = {0};
2035
0
    uint32_t i = 0, impl_opts;
2036
0
    struct ly_ht *getnext_ht = NULL;
2037
2038
0
    assert(tree && ctx);
2039
0
    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
2040
0
            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
2041
2042
0
    if (!node_when_p) {
2043
0
        node_when_p = &node_when;
2044
0
        node_types_p = &node_types;
2045
0
        meta_types_p = &meta_types;
2046
0
        ext_val_p = &ext_val;
2047
0
    }
2048
2049
0
    next = *tree;
2050
0
    while (1) {
2051
0
        if (val_opts & LYD_VALIDATE_PRESENT) {
2052
0
            mod = lyd_data_next_module(&next, &first);
2053
0
        } else {
2054
0
            mod = lyd_mod_next_module(next, module, ctx, &i, &first);
2055
0
        }
2056
0
        if (!mod) {
2057
0
            break;
2058
0
        }
2059
0
        if (!first || (first == *tree)) {
2060
            /* make sure first2 changes are carried to tree */
2061
0
            first2 = tree;
2062
0
        } else {
2063
0
            first2 = &first;
2064
0
        }
2065
2066
        /* create the getnext hash table for this module */
2067
0
        r = lyd_val_getnext_ht_new(&getnext_ht);
2068
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2069
2070
        /* store getnext_ht and module for final validation */
2071
0
        r = ly_set_add(&getnext_ht_set, getnext_ht, 1, NULL);
2072
0
        LY_CHECK_ERR_GOTO(r, lyd_val_getnext_ht_free(getnext_ht); rc = r, cleanup);
2073
0
        r = ly_set_add(&mod_set, mod, 1, NULL);
2074
0
        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2075
2076
        /* validate new top-level nodes of this module, autodelete */
2077
0
        r = lyd_validate_new(first2, *first2 ? lysc_data_parent((*first2)->schema) : NULL, mod, val_opts, 0,
2078
0
                getnext_ht, diff);
2079
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2080
2081
        /* add all top-level defaults for this module, if going to validate subtree, do not add into unres sets
2082
         * (lyd_validate_tree() adds all the nodes in that case) */
2083
0
        impl_opts = 0;
2084
0
        if (val_opts & LYD_VALIDATE_NO_STATE) {
2085
0
            impl_opts |= LYD_IMPLICIT_NO_STATE;
2086
0
        }
2087
0
        if (val_opts & LYD_VALIDATE_NO_DEFAULTS) {
2088
0
            impl_opts |= LYD_IMPLICIT_NO_DEFAULTS;
2089
0
        }
2090
0
        if (validate_subtree) {
2091
0
            r = lyd_new_implicit(lyd_parent(*first2), first2, NULL, mod, NULL, NULL, NULL, impl_opts, getnext_ht, diff);
2092
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2093
0
        } else {
2094
            /* descendants will not be validated, create them all */
2095
0
            r = lyd_new_implicit_r(lyd_parent(*first2), first2, NULL, mod, node_when_p, node_types_p, ext_val_p,
2096
0
                    impl_opts, getnext_ht, diff);
2097
0
            LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2098
0
        }
2099
2100
        /* our first module node pointer may no longer be the first */
2101
0
        first = *first2;
2102
0
        lyd_first_module_sibling(&first, mod);
2103
0
        if (!first || (first == *tree)) {
2104
0
            first2 = tree;
2105
0
        } else {
2106
0
            first2 = &first;
2107
0
        }
2108
2109
0
        if (validate_subtree) {
2110
            /* process nested nodes */
2111
0
            LY_LIST_FOR(*first2, iter) {
2112
0
                if (lyd_owner_module(iter) != mod) {
2113
0
                    break;
2114
0
                }
2115
2116
0
                r = lyd_validate_tree(iter, NULL, node_when_p, node_types_p, meta_types_p, ext_val_p, val_opts, 0,
2117
0
                        getnext_ht, diff);
2118
0
                LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2119
0
            }
2120
0
        }
2121
2122
        /* finish incompletely validated terminal values/attributes and when conditions */
2123
0
        r = lyd_validate_unres(first2, mod, LYD_TYPE_DATA_YANG, node_when_p, 0, node_types_p, meta_types_p,
2124
0
                ext_val_p, val_opts, diff);
2125
0
        LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2126
0
    }
2127
2128
0
    if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) {
2129
        /* perform final validation that assumes the data tree is final */
2130
0
        for (i = 0; i < mod_set.count; ++i) {
2131
0
            mod = mod_set.objs[i];
2132
0
            getnext_ht = getnext_ht_set.objs[i];
2133
2134
            /* find data of this module */
2135
0
            first = *tree;
2136
0
            lyd_first_module_sibling(&first, mod);
2137
2138
0
            r = lyd_validate_final_r(first, NULL, NULL, mod, NULL, val_opts, 0, 0, getnext_ht);
2139
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2140
0
        }
2141
0
    }
2142
2143
0
cleanup:
2144
0
    ly_set_erase(&node_when, NULL);
2145
0
    ly_set_erase(&node_types, NULL);
2146
0
    ly_set_erase(&meta_types, NULL);
2147
0
    ly_set_erase(&ext_val, free);
2148
0
    ly_set_erase(&mod_set, NULL);
2149
0
    ly_set_erase(&getnext_ht_set, lyd_val_getnext_ht_set_free);
2150
0
    return rc;
2151
0
}
2152
2153
LIBYANG_API_DEF LY_ERR
2154
lyd_validate_ext(struct lyd_node **subtree, const struct lysc_ext_instance *ext, uint32_t val_opts,
2155
        struct lyd_node **diff)
2156
0
{
2157
0
    LY_ERR r, rc = LY_SUCCESS;
2158
0
    struct ly_set subtree_skip = {0}, node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
2159
0
    struct ly_ht *getnext_ht = NULL;
2160
0
    struct lyd_node *iter;
2161
2162
0
    LY_CHECK_ARG_RET(NULL, subtree, !*subtree || (*subtree)->flags & LYD_EXT, ext, LY_EINVAL);
2163
2164
    /* remember all subtrees that should not be validated */
2165
0
    LY_LIST_FOR(lyd_first_sibling(*subtree), iter) {
2166
0
        if (iter != *subtree) {
2167
0
            ly_set_add(&subtree_skip, iter, 1, NULL);
2168
0
        }
2169
0
    }
2170
2171
    /* create the getnext hash table for these data */
2172
0
    r = lyd_val_getnext_ht_new(&getnext_ht);
2173
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2174
2175
    /* process nested nodes */
2176
0
    r = lyd_validate_tree(*subtree, ext, &node_when, &node_types, &meta_types, &ext_val, val_opts, 0,
2177
0
            getnext_ht, diff);
2178
0
    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2179
2180
    /* finish incompletely validated terminal values/attributes and when conditions */
2181
0
    r = lyd_validate_unres(subtree, NULL, LYD_TYPE_DATA_YANG, &node_when, 0, &node_types, &meta_types,
2182
0
            &ext_val, val_opts, diff);
2183
0
    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2184
2185
0
    if (!(val_opts & LYD_VALIDATE_NOT_FINAL)) {
2186
        /* perform final validation that assumes the data tree is final (on the subtree and any newly created ones) */
2187
0
        LY_LIST_FOR(lyd_first_sibling(*subtree), iter) {
2188
0
            if (ly_set_contains(&subtree_skip, iter, NULL)) {
2189
0
                continue;
2190
0
            }
2191
2192
0
            r = lyd_validate_final_r(iter, NULL, NULL, NULL, ext, val_opts, LYD_INTOPT_SKIP_SIBLINGS, 0, getnext_ht);
2193
0
            LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2194
0
        }
2195
0
    }
2196
2197
0
cleanup:
2198
0
    ly_set_erase(&subtree_skip, NULL);
2199
0
    ly_set_erase(&node_when, NULL);
2200
0
    ly_set_erase(&node_types, NULL);
2201
0
    ly_set_erase(&meta_types, NULL);
2202
0
    ly_set_erase(&ext_val, free);
2203
0
    lyd_val_getnext_ht_free(getnext_ht);
2204
0
    return rc;
2205
0
}
2206
2207
LIBYANG_API_DEF LY_ERR
2208
lyd_validate_all(struct lyd_node **tree, const struct ly_ctx *ctx, uint32_t val_opts, struct lyd_node **diff)
2209
0
{
2210
0
    LY_CHECK_ARG_RET(NULL, tree, *tree || ctx, LY_EINVAL);
2211
0
    LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, ctx, LY_EINVAL);
2212
0
    if (!ctx) {
2213
0
        ctx = LYD_CTX(*tree);
2214
0
    }
2215
0
    if (diff) {
2216
0
        *diff = NULL;
2217
0
    }
2218
2219
0
    return lyd_validate(tree, NULL, ctx, val_opts, 1, NULL, NULL, NULL, NULL, diff);
2220
0
}
2221
2222
LIBYANG_API_DEF LY_ERR
2223
lyd_validate_module(struct lyd_node **tree, const struct lys_module *module, uint32_t val_opts, struct lyd_node **diff)
2224
0
{
2225
0
    LY_CHECK_ARG_RET(NULL, tree, module, !(val_opts & LYD_VALIDATE_PRESENT), LY_EINVAL);
2226
0
    LY_CHECK_CTX_EQUAL_RET(__func__, *tree ? LYD_CTX(*tree) : NULL, module->ctx, LY_EINVAL);
2227
0
    if (diff) {
2228
0
        *diff = NULL;
2229
0
    }
2230
2231
0
    return lyd_validate(tree, module, module->ctx, val_opts, 1, NULL, NULL, NULL, NULL, diff);
2232
0
}
2233
2234
LIBYANG_API_DEF LY_ERR
2235
lyd_validate_module_final(struct lyd_node *tree, const struct lys_module *module, uint32_t val_opts)
2236
0
{
2237
0
    LY_ERR r, rc = LY_SUCCESS;
2238
0
    struct lyd_node *first;
2239
0
    const struct lys_module *mod;
2240
0
    uint32_t i = 0;
2241
0
    struct ly_ht *getnext_ht = NULL;
2242
2243
0
    LY_CHECK_ARG_RET(NULL, module, !(val_opts & (LYD_VALIDATE_PRESENT | LYD_VALIDATE_NOT_FINAL)), LY_EINVAL);
2244
0
    LY_CHECK_CTX_EQUAL_RET(__func__, tree ? LYD_CTX(tree) : NULL, module->ctx, LY_EINVAL);
2245
2246
    /* module is unchanged but we need to get the first module data node */
2247
0
    mod = lyd_mod_next_module(tree, module, module->ctx, &i, &first);
2248
0
    assert(mod);
2249
2250
    /* create the getnext hash table for this module */
2251
0
    r = lyd_val_getnext_ht_new(&getnext_ht);
2252
0
    LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
2253
2254
    /* perform final validation that assumes the data tree is final */
2255
0
    r = lyd_validate_final_r(first, NULL, NULL, mod, NULL, val_opts, 0, 0, getnext_ht);
2256
0
    LY_VAL_ERR_GOTO(r, rc = r, val_opts, cleanup);
2257
2258
0
cleanup:
2259
0
    lyd_val_getnext_ht_free(getnext_ht);
2260
0
    return rc;
2261
0
}
2262
2263
/**
2264
 * @brief Find nodes for merging an operation into data tree for validation.
2265
 *
2266
 * @param[in] op_tree Full operation data tree.
2267
 * @param[in] op_node Operation node itself.
2268
 * @param[in] tree Data tree to be merged into.
2269
 * @param[out] op_subtree Operation subtree to merge.
2270
 * @param[out] tree_sibling Data tree sibling to merge next to, is set if @p tree_parent is NULL.
2271
 * @param[out] tree_parent Data tree parent to merge into, is set if @p tree_sibling is NULL.
2272
 */
2273
static void
2274
lyd_val_op_merge_find(const struct lyd_node *op_tree, const struct lyd_node *op_node, const struct lyd_node *tree,
2275
        struct lyd_node **op_subtree, struct lyd_node **tree_sibling, struct lyd_node **tree_parent)
2276
0
{
2277
0
    const struct lyd_node *tree_iter, *op_iter;
2278
0
    struct lyd_node *match = NULL;
2279
0
    uint32_t i, cur_depth, op_depth;
2280
2281
0
    *op_subtree = NULL;
2282
0
    *tree_sibling = NULL;
2283
0
    *tree_parent = NULL;
2284
2285
    /* learn op depth (top-level being depth 0) */
2286
0
    op_depth = 0;
2287
0
    for (op_iter = op_node; op_iter != op_tree; op_iter = op_iter->parent) {
2288
0
        ++op_depth;
2289
0
    }
2290
2291
    /* find where to merge op */
2292
0
    tree_iter = tree;
2293
0
    cur_depth = op_depth;
2294
0
    while (cur_depth && tree_iter) {
2295
        /* find op iter in tree */
2296
0
        lyd_find_sibling_first(tree_iter, op_iter, &match);
2297
0
        if (!match) {
2298
0
            break;
2299
0
        }
2300
2301
        /* move tree_iter */
2302
0
        tree_iter = lyd_child(match);
2303
2304
        /* move depth */
2305
0
        --cur_depth;
2306
2307
        /* find next op parent */
2308
0
        op_iter = op_node;
2309
0
        for (i = 0; i < cur_depth; ++i) {
2310
0
            op_iter = op_iter->parent;
2311
0
        }
2312
0
    }
2313
2314
0
    assert(op_iter);
2315
0
    *op_subtree = (struct lyd_node *)op_iter;
2316
0
    if (!tree || tree_iter) {
2317
        /* there is no tree whatsoever or this is the last found sibling */
2318
0
        *tree_sibling = (struct lyd_node *)tree_iter;
2319
0
    } else {
2320
        /* matching parent was found but it has no children to insert next to */
2321
0
        assert(match);
2322
0
        *tree_parent = match;
2323
0
    }
2324
0
}
2325
2326
/**
2327
 * @brief Validate an RPC/action request, reply, or notification.
2328
 *
2329
 * @param[in] op_tree Full operation data tree.
2330
 * @param[in] op_node Operation node itself.
2331
 * @param[in] dep_tree Tree to be used for validating references from the operation subtree.
2332
 * @param[in] int_opts Internal parser options.
2333
 * @param[in] data_type Type of validated data.
2334
 * @param[in] validate_subtree Whether subtree was already validated (as part of data parsing) or not (separate validation).
2335
 * @param[in] node_when_p Set of nodes with when conditions, if NULL a local set is used.
2336
 * @param[in] node_types_p Set of unres node types, if NULL a local set is used.
2337
 * @param[in] meta_types_p Set of unres metadata types, if NULL a local set is used.
2338
 * @param[in] ext_val_p Set of parsed extension data to validate, if NULL a local set is used.
2339
 * @param[out] diff Optional diff with any changes made by the validation.
2340
 * @return LY_SUCCESS on success.
2341
 * @return LY_ERR error on error.
2342
 */
2343
static LY_ERR
2344
_lyd_validate_op(struct lyd_node *op_tree, struct lyd_node *op_node, const struct lyd_node *dep_tree, enum lyd_type data_type,
2345
        uint32_t int_opts, ly_bool validate_subtree, struct ly_set *node_when_p, struct ly_set *node_types_p,
2346
        struct ly_set *meta_types_p, struct ly_set *ext_val_p, struct lyd_node **diff)
2347
0
{
2348
0
    LY_ERR rc = LY_SUCCESS;
2349
0
    struct lyd_node *tree_sibling, *tree_parent, *op_subtree, *op_parent, *op_sibling_before, *op_sibling_after, *child;
2350
0
    struct ly_set node_types = {0}, meta_types = {0}, node_when = {0}, ext_val = {0};
2351
0
    struct ly_ht *getnext_ht = NULL;
2352
2353
0
    assert(op_tree && op_node);
2354
0
    assert((node_when_p && node_types_p && meta_types_p && ext_val_p) ||
2355
0
            (!node_when_p && !node_types_p && !meta_types_p && !ext_val_p));
2356
2357
0
    if (!node_when_p) {
2358
0
        node_when_p = &node_when;
2359
0
        node_types_p = &node_types;
2360
0
        meta_types_p = &meta_types;
2361
0
        ext_val_p = &ext_val;
2362
0
    }
2363
2364
    /* merge op_tree into dep_tree */
2365
0
    lyd_val_op_merge_find(op_tree, op_node, dep_tree, &op_subtree, &tree_sibling, &tree_parent);
2366
0
    op_sibling_before = op_subtree->prev->next ? op_subtree->prev : NULL;
2367
0
    op_sibling_after = op_subtree->next;
2368
0
    op_parent = op_subtree->parent;
2369
2370
0
    lyd_unlink(op_subtree);
2371
0
    lyd_insert_node(tree_parent, &tree_sibling, op_subtree, LYD_INSERT_NODE_DEFAULT);
2372
0
    if (!dep_tree) {
2373
0
        dep_tree = tree_sibling;
2374
0
    }
2375
2376
    /* create the getnext hash table for this module */
2377
0
    rc = lyd_val_getnext_ht_new(&getnext_ht);
2378
0
    LY_CHECK_GOTO(rc, cleanup);
2379
2380
0
    if (int_opts & LYD_INTOPT_REPLY) {
2381
0
        if (validate_subtree) {
2382
            /* add output children defaults */
2383
0
            rc = lyd_new_implicit(op_node, lyd_node_child_p(op_node), NULL, NULL, NULL, NULL, NULL,
2384
0
                    LYD_IMPLICIT_OUTPUT, getnext_ht, diff);
2385
0
            LY_CHECK_GOTO(rc, cleanup);
2386
2387
            /* skip validating the operation itself, go to children directly */
2388
0
            LY_LIST_FOR(lyd_child(op_node), child) {
2389
0
                rc = lyd_validate_tree(child, NULL, node_when_p, node_types_p, meta_types_p, ext_val_p, 0,
2390
0
                        int_opts, getnext_ht, diff);
2391
0
                LY_CHECK_GOTO(rc, cleanup);
2392
0
            }
2393
0
        } else {
2394
            /* add output children defaults and their descendants */
2395
0
            rc = lyd_new_implicit_r(op_node, lyd_node_child_p(op_node), NULL, NULL, node_when_p, node_types_p,
2396
0
                    ext_val_p, LYD_IMPLICIT_OUTPUT, getnext_ht, diff);
2397
0
            LY_CHECK_GOTO(rc, cleanup);
2398
0
        }
2399
0
    } else {
2400
0
        if (validate_subtree) {
2401
            /* prevalidate whole operation subtree */
2402
0
            rc = lyd_validate_tree(op_node, NULL, node_when_p, node_types_p, meta_types_p, ext_val_p, 0,
2403
0
                    int_opts, getnext_ht, diff);
2404
0
            LY_CHECK_GOTO(rc, cleanup);
2405
0
        }
2406
0
    }
2407
2408
    /* finish incompletely validated terminal values/attributes and when conditions on the full tree,
2409
     * account for unresolved 'when' that may appear in the non-validated dependency data tree */
2410
0
    LY_CHECK_GOTO(rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, node_when_p,
2411
0
            LYXP_IGNORE_WHEN, node_types_p, meta_types_p, ext_val_p, 0, diff), cleanup);
2412
2413
    /* perform final validation of the operation/notification */
2414
0
    lyd_validate_obsolete(op_node);
2415
0
    LY_CHECK_GOTO(rc = lyd_validate_must(op_node, 0, int_opts, LYXP_IGNORE_WHEN), cleanup);
2416
2417
    /* final validation of all the descendants */
2418
0
    rc = lyd_validate_final_r(lyd_child(op_node), op_node, op_node->schema, NULL, NULL, 0, int_opts, LYXP_IGNORE_WHEN,
2419
0
            getnext_ht);
2420
0
    LY_CHECK_GOTO(rc, cleanup);
2421
2422
0
cleanup:
2423
    /* restore operation tree */
2424
0
    lyd_unlink(op_subtree);
2425
0
    if (op_sibling_before) {
2426
0
        lyd_insert_after_node(NULL, op_sibling_before, op_subtree);
2427
0
        lyd_insert_hash(op_subtree);
2428
0
    } else if (op_sibling_after) {
2429
0
        lyd_insert_before_node(op_sibling_after, op_subtree);
2430
0
        lyd_insert_hash(op_subtree);
2431
0
    } else if (op_parent) {
2432
0
        lyd_insert_node(op_parent, NULL, op_subtree, LYD_INSERT_NODE_DEFAULT);
2433
0
    }
2434
2435
0
    ly_set_erase(&node_when, NULL);
2436
0
    ly_set_erase(&node_types, NULL);
2437
0
    ly_set_erase(&meta_types, NULL);
2438
0
    ly_set_erase(&ext_val, free);
2439
0
    lyd_val_getnext_ht_free(getnext_ht);
2440
0
    return rc;
2441
0
}
2442
2443
LIBYANG_API_DEF LY_ERR
2444
lyd_validate_op(struct lyd_node *op_tree, const struct lyd_node *dep_tree, enum lyd_type data_type, struct lyd_node **diff)
2445
0
{
2446
0
    struct lyd_node *op_node;
2447
0
    uint32_t int_opts;
2448
0
    struct ly_set ext_val = {0};
2449
0
    LY_ERR rc;
2450
2451
0
    LY_CHECK_ARG_RET(NULL, op_tree, !dep_tree || !dep_tree->parent, (data_type == LYD_TYPE_RPC_YANG) ||
2452
0
            (data_type == LYD_TYPE_NOTIF_YANG) || (data_type == LYD_TYPE_REPLY_YANG), LY_EINVAL);
2453
0
    if (op_tree == dep_tree) {
2454
        /* redundant dependency */
2455
0
        dep_tree = NULL;
2456
0
    }
2457
0
    if (diff) {
2458
0
        *diff = NULL;
2459
0
    }
2460
0
    if (data_type == LYD_TYPE_RPC_YANG) {
2461
0
        int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION;
2462
0
    } else if (data_type == LYD_TYPE_NOTIF_YANG) {
2463
0
        int_opts = LYD_INTOPT_NOTIF;
2464
0
    } else {
2465
0
        int_opts = LYD_INTOPT_REPLY;
2466
0
    }
2467
2468
0
    if (op_tree->schema && (op_tree->schema->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
2469
        /* we have the operation/notification, adjust the pointers */
2470
0
        op_node = op_tree;
2471
0
        while (op_tree->parent) {
2472
0
            op_tree = op_tree->parent;
2473
0
        }
2474
0
    } else {
2475
        /* find the operation/notification */
2476
0
        while (op_tree->parent) {
2477
0
            op_tree = op_tree->parent;
2478
0
        }
2479
0
        LYD_TREE_DFS_BEGIN(op_tree, op_node) {
2480
0
            if (!op_node->schema) {
2481
0
                return lyd_parse_opaq_error(op_node);
2482
0
            } else if (op_node->flags & LYD_EXT) {
2483
                /* fully validate the rest using the extension instance callback */
2484
0
                LY_CHECK_RET(lyd_validate_tree_ext(op_node, NULL, &ext_val));
2485
0
                rc = lyd_validate_unres((struct lyd_node **)&dep_tree, NULL, data_type, NULL, 0, NULL, NULL,
2486
0
                        &ext_val, 0, diff);
2487
0
                ly_set_erase(&ext_val, free);
2488
0
                return rc;
2489
0
            }
2490
2491
0
            if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) &&
2492
0
                    (op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
2493
0
                break;
2494
0
            } else if ((int_opts & LYD_INTOPT_NOTIF) && (op_node->schema->nodetype == LYS_NOTIF)) {
2495
0
                break;
2496
0
            }
2497
0
            LYD_TREE_DFS_END(op_tree, op_node);
2498
0
        }
2499
0
    }
2500
2501
0
    if (int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_REPLY)) {
2502
0
        if (!op_node || !(op_node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
2503
0
            LOGERR(LYD_CTX(op_tree), LY_EINVAL, "No RPC/action to validate found.");
2504
0
            return LY_EINVAL;
2505
0
        }
2506
0
    } else {
2507
0
        if (!op_node || (op_node->schema->nodetype != LYS_NOTIF)) {
2508
0
            LOGERR(LYD_CTX(op_tree), LY_EINVAL, "No notification to validate found.");
2509
0
            return LY_EINVAL;
2510
0
        }
2511
0
    }
2512
2513
    /* validate */
2514
0
    return _lyd_validate_op(op_tree, op_node, dep_tree, data_type, int_opts, 1, NULL, NULL, NULL, NULL, diff);
2515
0
}