blob: 887305fffa6473bb9a85f02050f8f3d226c2d5c2 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file parser_xml.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief XML data parser for libyang
5 *
6 * Copyright (c) 2019 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
Michal Vasko69730152020-10-09 16:30:07 +020015#include <assert.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "common.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "context.h"
Michal Vaskoafac7822020-10-20 14:22:26 +020022#include "in_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020023#include "log.h"
Radek Krejci7931b192020-06-25 17:05:03 +020024#include "parser_data.h"
25#include "parser_internal.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020026#include "set.h"
Radek Krejci47fab892020-11-05 17:02:41 +010027#include "tree_data.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020028#include "tree_data_internal.h"
29#include "tree_schema.h"
Michal Vaskocde73ac2019-11-14 16:10:27 +010030#include "validation.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020031#include "xml.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020032
33/**
Michal Vaskob36053d2020-03-26 15:49:30 +010034 * @brief Internal context for XML YANG data parser.
Radek Krejci1798aae2020-07-14 13:26:06 +020035 *
36 * Note that the structure maps to the lyd_ctx which is common for all the data parsers
Radek Krejcie7b95092019-05-15 11:03:07 +020037 */
38struct lyd_xml_ctx {
Michal Vaskoe0665742021-02-11 11:08:44 +010039 uint32_t parse_opts; /**< various @ref dataparseroptions. */
40 uint32_t val_opts; /**< various @ref datavalidationoptions. */
Radek Krejci1798aae2020-07-14 13:26:06 +020041 uint32_t int_opts; /**< internal data parser options */
42 uint32_t path_len; /**< used bytes in the path buffer */
43 char path[LYD_PARSER_BUFSIZE]; /**< buffer for the generated path */
Michal Vasko49c39d82020-11-06 17:20:27 +010044 struct ly_set node_types; /**< set of nodes validated with LY_EINCOMPLETE result */
45 struct ly_set meta_types; /**< set of metadata validated with LY_EINCOMPLETE result */
46 struct ly_set node_when; /**< set of nodes with "when" conditions */
Radek Krejci1798aae2020-07-14 13:26:06 +020047 struct lyd_node *op_node; /**< if an RPC/action/notification is being parsed, store the pointer to it */
Radek Krejcie7b95092019-05-15 11:03:07 +020048
Radek Krejci1798aae2020-07-14 13:26:06 +020049 /* callbacks */
50 lyd_ctx_free_clb free; /* destructor */
Radek Krejci1798aae2020-07-14 13:26:06 +020051
52 struct lyxml_ctx *xmlctx; /**< XML context */
Radek Krejcie7b95092019-05-15 11:03:07 +020053};
54
Radek Krejci1798aae2020-07-14 13:26:06 +020055void
56lyd_xml_ctx_free(struct lyd_ctx *lydctx)
57{
58 struct lyd_xml_ctx *ctx = (struct lyd_xml_ctx *)lydctx;
59
60 lyd_ctx_free(lydctx);
61 lyxml_ctx_free(ctx->xmlctx);
62 free(ctx);
63}
64
Radek Krejcie7b95092019-05-15 11:03:07 +020065static LY_ERR
Michal Vaskofeca4fb2020-10-05 08:58:40 +020066lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lyd_meta **meta)
Radek Krejcie7b95092019-05-15 11:03:07 +020067{
Michal Vaskob36053d2020-03-26 15:49:30 +010068 LY_ERR ret = LY_EVALID;
Radek Krejci28681fa2019-09-06 13:08:45 +020069 const struct lyxml_ns *ns;
70 struct lys_module *mod;
Michal Vaskob36053d2020-03-26 15:49:30 +010071 const char *name;
72 size_t name_len;
Radek Krejci1798aae2020-07-14 13:26:06 +020073 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
Radek Krejci28681fa2019-09-06 13:08:45 +020074
Michal Vaskob36053d2020-03-26 15:49:30 +010075 *meta = NULL;
Radek Krejci28681fa2019-09-06 13:08:45 +020076
Michal Vaskob36053d2020-03-26 15:49:30 +010077 while (xmlctx->status == LYXML_ATTRIBUTE) {
78 if (!xmlctx->prefix_len) {
Radek Krejci28681fa2019-09-06 13:08:45 +020079 /* in XML, all attributes must be prefixed
80 * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
Michal Vaskoe0665742021-02-11 11:08:44 +010081 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +010082 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Missing mandatory prefix for XML metadata \"%.*s\".",
Michal Vasko69730152020-10-09 16:30:07 +020083 xmlctx->name_len, xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +010084 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +020085 }
Michal Vaskob36053d2020-03-26 15:49:30 +010086
Radek Krejci28681fa2019-09-06 13:08:45 +020087skip_attr:
Michal Vaskob36053d2020-03-26 15:49:30 +010088 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
89 assert(xmlctx->status == LYXML_ATTR_CONTENT);
90 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejci28681fa2019-09-06 13:08:45 +020091 continue;
92 }
93
94 /* get namespace of the attribute to find its annotation definition */
Michal Vaskoc8a230d2020-08-14 12:17:10 +020095 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Radek Krejci28681fa2019-09-06 13:08:45 +020096 if (!ns) {
Michal Vasko52927e22020-03-16 17:26:14 +010097 /* unknown namespace, XML error */
Radek Krejci2efc45b2020-12-22 16:25:44 +010098 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Radek Krejci28681fa2019-09-06 13:08:45 +020099 goto cleanup;
100 }
Michal Vasko52927e22020-03-16 17:26:14 +0100101 mod = ly_ctx_get_module_implemented_ns(xmlctx->ctx, ns->uri);
Radek Krejci28681fa2019-09-06 13:08:45 +0200102 if (!mod) {
103 /* module is not implemented or not present in the schema */
Michal Vaskoe0665742021-02-11 11:08:44 +0100104 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100105 LOGVAL(xmlctx->ctx, LYVE_REFERENCE,
Michal Vasko69730152020-10-09 16:30:07 +0200106 "Unknown (or not implemented) YANG module with namespace \"%s\" for metadata \"%.*s%s%.*s\".",
107 ns->uri, xmlctx->prefix_len, xmlctx->prefix, xmlctx->prefix_len ? ":" : "", xmlctx->name_len,
108 xmlctx->name);
Michal Vaskob36053d2020-03-26 15:49:30 +0100109 goto cleanup;
Radek Krejci28681fa2019-09-06 13:08:45 +0200110 }
111 goto skip_attr;
112 }
113
Michal Vasko60ea6352020-06-29 13:39:39 +0200114 /* remember meta name and get its content */
Michal Vaskob36053d2020-03-26 15:49:30 +0100115 name = xmlctx->name;
116 name_len = xmlctx->name_len;
117 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
118 assert(xmlctx->status == LYXML_ATTR_CONTENT);
119
120 /* create metadata */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200121 ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200122 xmlctx->value_len, &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA);
Radek Krejci1798aae2020-07-14 13:26:06 +0200123 LY_CHECK_GOTO(ret, cleanup);
Michal Vaskob36053d2020-03-26 15:49:30 +0100124
125 /* next attribute */
126 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Radek Krejcie7b95092019-05-15 11:03:07 +0200127 }
Michal Vasko52927e22020-03-16 17:26:14 +0100128
Radek Krejci28681fa2019-09-06 13:08:45 +0200129 ret = LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200130
131cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100132 if (ret) {
Michal Vasko3a41dff2020-07-15 14:30:28 +0200133 lyd_free_meta_siblings(*meta);
Michal Vaskob36053d2020-03-26 15:49:30 +0100134 *meta = NULL;
Radek Krejci38d85362019-09-05 16:26:38 +0200135 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200136 return ret;
137}
138
Michal Vasko52927e22020-03-16 17:26:14 +0100139static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200140lydxml_attrs(struct lyxml_ctx *xmlctx, struct lyd_attr **attr)
Michal Vasko52927e22020-03-16 17:26:14 +0100141{
142 LY_ERR ret = LY_SUCCESS;
143 const struct lyxml_ns *ns;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100144 void *val_prefix_data;
145 LY_PREFIX_FORMAT format;
Radek Krejci1798aae2020-07-14 13:26:06 +0200146 struct lyd_attr *attr2;
Michal Vaskob36053d2020-03-26 15:49:30 +0100147 const char *name, *prefix;
148 size_t name_len, prefix_len;
Michal Vasko52927e22020-03-16 17:26:14 +0100149
150 assert(attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100151 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100152
Michal Vaskob36053d2020-03-26 15:49:30 +0100153 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vasko52927e22020-03-16 17:26:14 +0100154 ns = NULL;
Michal Vaskob36053d2020-03-26 15:49:30 +0100155 if (xmlctx->prefix_len) {
Michal Vasko52927e22020-03-16 17:26:14 +0100156 /* get namespace of the attribute */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200157 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
Michal Vasko52927e22020-03-16 17:26:14 +0100158 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100159 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
Michal Vasko52927e22020-03-16 17:26:14 +0100160 ret = LY_EVALID;
161 goto cleanup;
162 }
163 }
164
165 if (*attr) {
166 attr2 = *attr;
167 } else {
168 attr2 = NULL;
169 }
170
Michal Vaskob36053d2020-03-26 15:49:30 +0100171 /* remember attr prefix, name, and get its content */
172 prefix = xmlctx->prefix;
173 prefix_len = xmlctx->prefix_len;
174 name = xmlctx->name;
175 name_len = xmlctx->name_len;
176 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
177 assert(xmlctx->status == LYXML_ATTR_CONTENT);
178
Michal Vasko52927e22020-03-16 17:26:14 +0100179 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100180 LY_CHECK_GOTO(ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
181 &xmlctx->ns, &format, &val_prefix_data), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100182
183 /* attr2 is always changed to the created attribute */
Michal Vasko501af032020-11-11 20:27:44 +0100184 ret = lyd_create_attr(NULL, &attr2, xmlctx->ctx, name, name_len, prefix, prefix_len, ns ? ns->uri : NULL,
185 ns ? strlen(ns->uri) : 0, xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, 0);
Michal Vasko52927e22020-03-16 17:26:14 +0100186 LY_CHECK_GOTO(ret, cleanup);
187
188 if (!*attr) {
189 *attr = attr2;
190 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100191
192 /* next attribute */
193 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko52927e22020-03-16 17:26:14 +0100194 }
195
196cleanup:
Michal Vaskob36053d2020-03-26 15:49:30 +0100197 if (ret) {
Radek Krejci011e4aa2020-09-04 15:22:31 +0200198 lyd_free_attr_siblings(xmlctx->ctx, *attr);
Michal Vaskob36053d2020-03-26 15:49:30 +0100199 *attr = NULL;
Michal Vasko52927e22020-03-16 17:26:14 +0100200 }
Michal Vasko52927e22020-03-16 17:26:14 +0100201 return ret;
202}
203
Michal Vasko44685da2020-03-17 15:38:06 +0100204static LY_ERR
Michal Vaskob36053d2020-03-26 15:49:30 +0100205lydxml_check_list(struct lyxml_ctx *xmlctx, const struct lysc_node *list)
Michal Vasko44685da2020-03-17 15:38:06 +0100206{
Michal Vaskob36053d2020-03-26 15:49:30 +0100207 LY_ERR ret = LY_SUCCESS, r;
208 enum LYXML_PARSER_STATUS next;
Michal Vasko44685da2020-03-17 15:38:06 +0100209 struct ly_set key_set = {0};
210 const struct lysc_node *snode;
Michal Vaskob36053d2020-03-26 15:49:30 +0100211 uint32_t i, parents_count;
Michal Vasko44685da2020-03-17 15:38:06 +0100212
213 assert(list && (list->nodetype == LYS_LIST));
214
215 /* get all keys into a set (keys do not have if-features or anything) */
216 snode = NULL;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100217 while ((snode = lys_getnext(snode, list, NULL, 0)) && (snode->flags & LYS_KEY)) {
Radek Krejci3d92e442020-10-12 12:48:13 +0200218 ret = ly_set_add(&key_set, (void *)snode, 1, NULL);
Radek Krejciba03a5a2020-08-27 14:40:41 +0200219 LY_CHECK_GOTO(ret, cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100220 }
221
Michal Vaskob36053d2020-03-26 15:49:30 +0100222 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vasko44685da2020-03-17 15:38:06 +0100223 /* find key definition */
224 for (i = 0; i < key_set.count; ++i) {
225 snode = (const struct lysc_node *)key_set.objs[i];
Michal Vaskob36053d2020-03-26 15:49:30 +0100226 if (!ly_strncmp(snode->name, xmlctx->name, xmlctx->name_len)) {
Michal Vasko44685da2020-03-17 15:38:06 +0100227 break;
228 }
229 }
Michal Vaskob36053d2020-03-26 15:49:30 +0100230 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100231
232 /* skip attributes */
233 while (xmlctx->status == LYXML_ATTRIBUTE) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100234 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
235 assert(xmlctx->status == LYXML_ATTR_CONTENT);
236 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100237 }
238
Michal Vaskob36053d2020-03-26 15:49:30 +0100239 assert(xmlctx->status == LYXML_ELEM_CONTENT);
240 if (i < key_set.count) {
241 /* validate the value */
Michal Vasko713148b2020-11-12 13:10:13 +0100242 r = _lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns);
Michal Vaskob36053d2020-03-26 15:49:30 +0100243 if (!r) {
244 /* key with a valid value, remove from the set */
245 ly_set_rm_index(&key_set, i, NULL);
Michal Vasko44685da2020-03-17 15:38:06 +0100246 }
247 }
248
Michal Vaskob36053d2020-03-26 15:49:30 +0100249 /* parser next */
250 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
Michal Vasko44685da2020-03-17 15:38:06 +0100251
Michal Vaskob36053d2020-03-26 15:49:30 +0100252 /* skip any children, resursively */
253 parents_count = xmlctx->elements.count;
254 while ((parents_count < xmlctx->elements.count) || (xmlctx->status == LYXML_ELEMENT)) {
255 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
256 }
257
258 /* parser next, but do not parse closing element of the list because it would remove its namespaces */
259 assert(xmlctx->status == LYXML_ELEM_CLOSE);
260 LY_CHECK_GOTO(ret = lyxml_ctx_peek(xmlctx, &next), cleanup);
261 if (next != LYXML_ELEM_CLOSE) {
262 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), cleanup);
263 }
Michal Vasko44685da2020-03-17 15:38:06 +0100264 }
265
266 if (key_set.count) {
Michal Vaskob36053d2020-03-26 15:49:30 +0100267 /* some keys are missing/did not validate */
Michal Vasko44685da2020-03-17 15:38:06 +0100268 ret = LY_ENOT;
Michal Vasko44685da2020-03-17 15:38:06 +0100269 }
270
271cleanup:
272 ly_set_erase(&key_set, NULL);
273 return ret;
274}
275
Michal Vasko1bf09392020-03-27 12:38:10 +0100276static LY_ERR
277lydxml_data_skip(struct lyxml_ctx *xmlctx)
278{
279 uint32_t parents_count;
280
281 /* remember current number of parents */
282 parents_count = xmlctx->elements.count;
283
284 /* skip after the content */
285 while (xmlctx->status != LYXML_ELEM_CONTENT) {
286 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
287 }
288 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
289
290 /* skip all children elements, recursively, if any */
291 while (parents_count < xmlctx->elements.count) {
292 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
293 }
294
295 /* close element */
296 assert(xmlctx->status == LYXML_ELEM_CLOSE);
297 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
298
299 return LY_SUCCESS;
300}
301
302static LY_ERR
Radek Krejci1798aae2020-07-14 13:26:06 +0200303lydxml_data_check_opaq(struct lyd_xml_ctx *lydctx, const struct lysc_node **snode)
Michal Vasko1bf09392020-03-27 12:38:10 +0100304{
305 LY_ERR ret = LY_SUCCESS;
306 enum LYXML_PARSER_STATUS prev_status;
Michal Vasko63f3d842020-07-08 10:10:14 +0200307 const char *prev_current, *pname, *pprefix;
Michal Vasko1bf09392020-03-27 12:38:10 +0100308 size_t pprefix_len, pname_len;
309 struct lyxml_ctx *xmlctx = lydctx->xmlctx;
310
Michal Vaskoe0665742021-02-11 11:08:44 +0100311 if ((lydctx->parse_opts & LYD_PARSE_OPAQ) && ((*snode)->nodetype & (LYD_NODE_TERM | LYS_LIST))) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100312 /* backup parser */
313 prev_status = xmlctx->status;
314 pprefix = xmlctx->prefix;
315 pprefix_len = xmlctx->prefix_len;
316 pname = xmlctx->name;
317 pname_len = xmlctx->name_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200318 prev_current = xmlctx->in->current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100319 if ((xmlctx->status == LYXML_ELEM_CONTENT) && xmlctx->dynamic) {
320 /* it was backed up, do not free */
321 xmlctx->dynamic = 0;
322 }
323
324 /* skip attributes */
325 while (xmlctx->status == LYXML_ATTRIBUTE) {
326 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
327 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
328 }
329
330 if ((*snode)->nodetype & LYD_NODE_TERM) {
331 /* value may not be valid in which case we parse it as an opaque node */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200332 if (_lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_PREF_XML, &xmlctx->ns)) {
Michal Vasko1bf09392020-03-27 12:38:10 +0100333 *snode = NULL;
334 }
335 } else {
336 /* skip content */
337 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), restore);
338
339 if (lydxml_check_list(xmlctx, *snode)) {
340 /* invalid list, parse as opaque if it missing/has invalid some keys */
341 *snode = NULL;
342 }
343 }
344
345restore:
346 /* restore parser */
347 if (xmlctx->dynamic) {
348 free((char *)xmlctx->value);
349 }
350 xmlctx->status = prev_status;
351 xmlctx->prefix = pprefix;
352 xmlctx->prefix_len = pprefix_len;
353 xmlctx->name = pname;
354 xmlctx->name_len = pname_len;
Michal Vasko63f3d842020-07-08 10:10:14 +0200355 xmlctx->in->current = prev_current;
Michal Vasko1bf09392020-03-27 12:38:10 +0100356 }
357
358 return ret;
359}
360
Radek Krejcie7b95092019-05-15 11:03:07 +0200361/**
Michal Vaskoa5da3292020-08-12 13:10:50 +0200362 * @brief Parse XML subtree.
Radek Krejcie7b95092019-05-15 11:03:07 +0200363 *
Michal Vaskob36053d2020-03-26 15:49:30 +0100364 * @param[in] lydctx XML YANG data parser context.
Michal Vaskoe0665742021-02-11 11:08:44 +0100365 * @param[in,out] parent Parent node where the children are inserted. NULL in case of parsing top-level elements.
366 * @param[in,out] first_p Pointer to the first (@p parent or top-level) child. In case there were already some siblings,
367 * this may point to a previously existing node.
368 * @param[in,out] parsed Optional set to add all the parsed siblings into.
Michal Vasko9b368d32020-02-14 13:53:31 +0100369 * @return LY_ERR value.
Radek Krejcie7b95092019-05-15 11:03:07 +0200370 */
371static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100372lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
Radek Krejcie7b95092019-05-15 11:03:07 +0200373{
Michal Vaskob36053d2020-03-26 15:49:30 +0100374 LY_ERR ret = LY_SUCCESS;
Michal Vasko1bf09392020-03-27 12:38:10 +0100375 const char *prefix, *name;
376 size_t prefix_len, name_len;
Michal Vaskob36053d2020-03-26 15:49:30 +0100377 struct lyxml_ctx *xmlctx;
378 const struct ly_ctx *ctx;
Radek Krejcie7b95092019-05-15 11:03:07 +0200379 const struct lyxml_ns *ns;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200380 struct lyd_meta *meta = NULL;
381 struct lyd_attr *attr = NULL;
Radek Krejcie7b95092019-05-15 11:03:07 +0200382 const struct lysc_node *snode;
383 struct lys_module *mod;
Michal Vasko1bf09392020-03-27 12:38:10 +0100384 uint32_t prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200385 struct lyd_node *node = NULL, *anchor;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100386 void *val_prefix_data;
387 LY_PREFIX_FORMAT format;
Radek Krejci1deb5be2020-08-26 16:43:36 +0200388 uint32_t getnext_opts;
Radek Krejcie7b95092019-05-15 11:03:07 +0200389
Michal Vaskoe0665742021-02-11 11:08:44 +0100390 assert(parent || first_p);
391
Michal Vaskob36053d2020-03-26 15:49:30 +0100392 xmlctx = lydctx->xmlctx;
393 ctx = xmlctx->ctx;
Michal Vasko7b1ad1a2020-11-02 15:41:27 +0100394 getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
Michal Vasko6f4cbb62020-02-28 11:15:47 +0100395
Michal Vaskoa5da3292020-08-12 13:10:50 +0200396 assert(xmlctx->status == LYXML_ELEMENT);
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200397
Michal Vaskoa5da3292020-08-12 13:10:50 +0200398 /* remember element prefix and name */
399 prefix = xmlctx->prefix;
400 prefix_len = xmlctx->prefix_len;
401 name = xmlctx->name;
402 name_len = xmlctx->name_len;
403
404 /* get the element module */
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200405 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200406 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100407 LOGVAL(ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200408 ret = LY_EVALID;
409 goto error;
410 }
411 mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
412 if (!mod) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100413 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100414 LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
Michal Vasko90932a92020-02-12 14:33:03 +0100415 ret = LY_EVALID;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200416 goto error;
Radek Krejcie7b95092019-05-15 11:03:07 +0200417 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100418 if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200419 /* skip element with children */
420 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
421 return LY_SUCCESS;
Radek Krejcie7b95092019-05-15 11:03:07 +0200422 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200423 }
424
Michal Vaskoa5da3292020-08-12 13:10:50 +0200425 /* parser next */
426 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
Michal Vasko90932a92020-02-12 14:33:03 +0100427
Michal Vaskoa5da3292020-08-12 13:10:50 +0200428 /* get the schema node */
429 snode = NULL;
430 if (mod && (!parent || parent->schema)) {
431 snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
432 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100433 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
434 if (parent) {
435 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.", name_len, name,
436 parent->schema->name);
437 } else {
438 LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found in the \"%s\" module.", name_len, name,
439 mod->name);
440 }
Michal Vaskoa5da3292020-08-12 13:10:50 +0200441 ret = LY_EVALID;
442 goto error;
Michal Vaskoe0665742021-02-11 11:08:44 +0100443 } else if (!(lydctx->parse_opts & LYD_PARSE_OPAQ)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200444 /* skip element with children */
445 LY_CHECK_GOTO(ret = lydxml_data_skip(xmlctx), error);
446 return LY_SUCCESS;
447 }
448 } else {
449 /* check that schema node is valid and can be used */
450 LY_CHECK_GOTO(ret = lyd_parser_check_schema((struct lyd_ctx *)lydctx, snode), error);
451 LY_CHECK_GOTO(ret = lydxml_data_check_opaq(lydctx, &snode), error);
452 }
453 }
454
455 /* create metadata/attributes */
456 if (xmlctx->status == LYXML_ATTRIBUTE) {
457 if (snode) {
Michal Vaskofeca4fb2020-10-05 08:58:40 +0200458 ret = lydxml_metadata(lydctx, &meta);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200459 LY_CHECK_GOTO(ret, error);
460 } else {
Michal Vaskoe0665742021-02-11 11:08:44 +0100461 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200462 ret = lydxml_attrs(xmlctx, &attr);
463 LY_CHECK_GOTO(ret, error);
464 }
465 }
466
467 assert(xmlctx->status == LYXML_ELEM_CONTENT);
468 if (!snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100469 assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200470
471 if (xmlctx->ws_only) {
472 /* ignore WS-only value */
473 xmlctx->value_len = 0;
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100474 val_prefix_data = NULL;
475 format = LY_PREF_XML;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200476 } else {
477 /* get value prefixes */
Michal Vasko6b5cb2a2020-11-11 19:11:21 +0100478 ret = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_PREF_XML,
479 &xmlctx->ns, &format, &val_prefix_data);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200480 LY_CHECK_GOTO(ret, error);
481 }
482
483 /* create node */
Michal Vasko501af032020-11-11 20:27:44 +0100484 ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
485 xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200486 LY_CHECK_GOTO(ret, error);
487
488 /* parser next */
489 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
490
491 /* process children */
492 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100493 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200494 LY_CHECK_GOTO(ret, error);
495 }
496 } else if (snode->nodetype & LYD_NODE_TERM) {
497 /* create node */
Michal Vasko22df3f02020-08-24 13:29:22 +0200498 LY_CHECK_GOTO(ret = lyd_parser_create_term((struct lyd_ctx *)lydctx, snode, xmlctx->value, xmlctx->value_len,
Michal Vasko69730152020-10-09 16:30:07 +0200499 &xmlctx->dynamic, LY_PREF_XML, &xmlctx->ns, LYD_HINT_DATA, &node), error);
Radek Krejciddace2c2021-01-08 11:30:56 +0100500 LOG_LOCSET(snode, node, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200501
502 if (parent && (node->schema->flags & LYS_KEY)) {
503 /* check the key order, the anchor must never be a key */
Michal Vaskoe0665742021-02-11 11:08:44 +0100504 anchor = lyd_insert_get_next_anchor(lyd_child(parent), node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200505 if (anchor && (anchor->schema->flags & LYS_KEY)) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100506 if (lydctx->parse_opts & LYD_PARSE_STRICT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100507 LOGVAL(ctx, LYVE_DATA, "Invalid position of the key \"%s\" in a list.", node->schema->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200508 ret = LY_EVALID;
509 goto error;
510 } else {
511 LOGWRN(ctx, "Invalid position of the key \"%s\" in a list.", node->schema->name);
512 }
513 }
514 }
515
516 /* parser next */
517 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
518
519 /* no children expected */
520 if (xmlctx->status == LYXML_ELEMENT) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100521 LOGVAL(ctx, LYVE_SYNTAX, "Child element \"%.*s\" inside a terminal node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200522 xmlctx->name_len, xmlctx->name, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200523 ret = LY_EVALID;
524 goto error;
525 }
526 } else if (snode->nodetype & LYD_NODE_INNER) {
527 if (!xmlctx->ws_only) {
528 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100529 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an inner node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200530 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200531 ret = LY_EVALID;
532 goto error;
533 }
534
535 /* create node */
536 ret = lyd_create_inner(snode, &node);
537 LY_CHECK_GOTO(ret, error);
538
Radek Krejciddace2c2021-01-08 11:30:56 +0100539 LOG_LOCSET(snode, node, NULL, NULL);
Radek Krejci2efc45b2020-12-22 16:25:44 +0100540
Michal Vaskoa5da3292020-08-12 13:10:50 +0200541 /* parser next */
542 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
543
544 /* process children */
545 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100546 ret = lydxml_subtree_r(lydctx, node, lyd_node_child_p(node), NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200547 LY_CHECK_GOTO(ret, error);
548 }
549
550 if (snode->nodetype == LYS_LIST) {
551 /* check all keys exist */
552 LY_CHECK_GOTO(ret = lyd_parse_check_keys(node), error);
553 }
554
Michal Vaskoe0665742021-02-11 11:08:44 +0100555 if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
Michal Vaskoa5da3292020-08-12 13:10:50 +0200556 /* new node validation, autodelete CANNOT occur, all nodes are new */
Michal Vaskoe0665742021-02-11 11:08:44 +0100557 ret = lyd_validate_new(lyd_node_child_p(node), snode, NULL, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200558 LY_CHECK_GOTO(ret, error);
559
560 /* add any missing default children */
Michal Vaskoe0665742021-02-11 11:08:44 +0100561 ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_types, &lydctx->node_when,
562 (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200563 LY_CHECK_GOTO(ret, error);
564 }
565
566 if (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)) {
567 /* rememeber the RPC/action/notification */
568 lydctx->op_node = node;
569 }
570 } else if (snode->nodetype & LYD_NODE_ANY) {
571 if (!xmlctx->ws_only) {
572 /* value in inner node */
Radek Krejci2efc45b2020-12-22 16:25:44 +0100573 LOGVAL(ctx, LYVE_SYNTAX, "Text value \"%.*s\" inside an any node \"%s\" found.",
Michal Vasko69730152020-10-09 16:30:07 +0200574 xmlctx->value_len, xmlctx->value, snode->name);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200575 ret = LY_EVALID;
576 goto error;
577 }
578
579 /* parser next */
580 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
581
582 /* parse any data tree with correct options */
Michal Vaskoe0665742021-02-11 11:08:44 +0100583 prev_opts = lydctx->parse_opts;
584 lydctx->parse_opts &= ~LYD_PARSE_STRICT;
585 lydctx->parse_opts |= LYD_PARSE_OPAQ;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200586 anchor = NULL;
587 while (xmlctx->status == LYXML_ELEMENT) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100588 ret = lydxml_subtree_r(lydctx, NULL, &anchor, NULL);
589 LY_CHECK_ERR_GOTO(ret, lydctx->parse_opts = prev_opts, error);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200590 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100591 lydctx->parse_opts = prev_opts;
Michal Vaskoa5da3292020-08-12 13:10:50 +0200592
593 /* create node */
Michal Vasko366a4a12020-12-04 16:23:57 +0100594 ret = lyd_create_any(snode, anchor, LYD_ANYDATA_DATATREE, 1, &node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200595 LY_CHECK_GOTO(ret, error);
596 }
597 assert(node);
598
599 /* add/correct flags */
600 if (snode) {
Michal Vaskoe0665742021-02-11 11:08:44 +0100601 lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200602 }
603
604 /* parser next */
605 assert(xmlctx->status == LYXML_ELEM_CLOSE);
606 LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
607
608 /* add metadata/attributes */
609 if (snode) {
Michal Vasko871a0252020-11-11 18:35:24 +0100610 lyd_insert_meta(node, meta, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200611 } else {
612 lyd_insert_attr(node, attr);
613 }
614
615 /* insert, keep first pointer correct */
Michal Vaskoe0665742021-02-11 11:08:44 +0100616 lyd_insert_node(parent, first_p, node);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200617 while (!parent && (*first_p)->prev->next) {
618 *first_p = (*first_p)->prev;
619 }
620
Michal Vaskoe0665742021-02-11 11:08:44 +0100621 /* rememeber a successfully parsed node */
622 if (parsed) {
623 ly_set_add(parsed, node, 1, NULL);
624 }
625
Radek Krejciddace2c2021-01-08 11:30:56 +0100626 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200627 return LY_SUCCESS;
628
629error:
Radek Krejciddace2c2021-01-08 11:30:56 +0100630 LOG_LOCBACK(node ? 1 : 0, node ? 1 : 0, 0, 0);
Michal Vasko3a41dff2020-07-15 14:30:28 +0200631 lyd_free_meta_siblings(meta);
Radek Krejci011e4aa2020-09-04 15:22:31 +0200632 lyd_free_attr_siblings(ctx, attr);
Michal Vaskoa5da3292020-08-12 13:10:50 +0200633 lyd_free_tree(node);
Radek Krejcie7b95092019-05-15 11:03:07 +0200634 return ret;
635}
636
Michal Vaskoe0665742021-02-11 11:08:44 +0100637/**
638 * @brief Parse a specific XML element into an opaque node.
639 *
640 * @param[in] xmlctx XML parser context.
641 * @param[in] name Name of the element.
642 * @param[in] uri URI of the element.
643 * @param[in] value Whether a value is expected in the element.
644 * @param[out] evnp Parsed envelope (opaque node).
645 * @return LY_SUCCESS on success.
646 * @return LY_ENOT if the specified element did not match.
647 * @return LY_ERR value on error.
648 */
Michal Vasko1bf09392020-03-27 12:38:10 +0100649static LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +0100650lydxml_envelope(struct lyxml_ctx *xmlctx, const char *name, const char *uri, ly_bool value, struct lyd_node **envp)
Michal Vasko1bf09392020-03-27 12:38:10 +0100651{
Michal Vaskoe0665742021-02-11 11:08:44 +0100652 LY_ERR rc = LY_SUCCESS;
653 const struct lyxml_ns *ns;
Radek Krejci1798aae2020-07-14 13:26:06 +0200654 struct lyd_attr *attr = NULL;
Michal Vasko1bf09392020-03-27 12:38:10 +0100655 const char *prefix;
656 size_t prefix_len;
657
Michal Vasko1bf09392020-03-27 12:38:10 +0100658 assert(xmlctx->status == LYXML_ELEMENT);
659 if (ly_strncmp(name, xmlctx->name, xmlctx->name_len)) {
660 /* not the expected element */
Michal Vaskoe0665742021-02-11 11:08:44 +0100661 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100662 }
663
664 prefix = xmlctx->prefix;
665 prefix_len = xmlctx->prefix_len;
Michal Vaskoc8a230d2020-08-14 12:17:10 +0200666 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100667 if (!ns) {
Radek Krejci2efc45b2020-12-22 16:25:44 +0100668 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
Michal Vaskoe0665742021-02-11 11:08:44 +0100669 return LY_EVALID;
670 } else if (strcmp(ns->uri, uri)) {
671 /* different namespace */
672 return LY_ENOT;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100673 }
674
675 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
676
677 /* create attributes */
678 if (xmlctx->status == LYXML_ATTRIBUTE) {
679 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
680 }
681
Michal Vaskoe0665742021-02-11 11:08:44 +0100682 assert(xmlctx->status == LYXML_ELEM_CONTENT);
683 if (!value && !xmlctx->ws_only) {
684 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected value \"%.*s\" in the \"%s\" element.",
685 xmlctx->value_len, xmlctx->value, name);
686 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100687 goto cleanup;
Michal Vaskoe0665742021-02-11 11:08:44 +0100688 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100689
690 /* create node */
Michal Vaskoe0665742021-02-11 11:08:44 +0100691 rc = lyd_create_opaq(xmlctx->ctx, name, strlen(name), prefix, prefix_len, uri, strlen(uri), xmlctx->value,
692 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, envp);
693 LY_CHECK_GOTO(rc, cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100694
695 /* assign atributes */
Michal Vaskoe0665742021-02-11 11:08:44 +0100696 ((struct lyd_node_opaq *)(*envp))->attr = attr;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100697 attr = NULL;
698
Michal Vaskoe0665742021-02-11 11:08:44 +0100699 /* parser next element */
700 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100701
Michal Vaskoe0665742021-02-11 11:08:44 +0100702cleanup:
703 lyd_free_attr_siblings(xmlctx->ctx, attr);
704 if (rc) {
705 lyd_free_tree(*envp);
706 *envp = NULL;
707 }
708 return rc;
709}
710
711/**
712 * @brief Parse all expected non-data XML elements of a NETCONF rpc message.
713 *
714 * @param[in] xmlctx XML parser context.
715 * @param[out] evnp Parsed envelope(s) (opaque node).
716 * @param[out] int_opts Internal options for parsing the rest of YANG data.
717 * @param[out] close_elem Number of parsed opened elements that need to be closed.
718 * @return LY_SUCCESS on success.
719 * @return LY_ERR value on error.
720 */
721static LY_ERR
722lydxml_env_netconf_rpc(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
723{
724 LY_ERR rc = LY_SUCCESS, r;
725 struct lyd_node *child;
726
727 assert(envp && !*envp);
728
729 /* parse "rpc" */
730 r = lydxml_envelope(xmlctx, "rpc", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
731 if (r == LY_ENOT) {
732 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"rpc\".", xmlctx->name_len,
733 xmlctx->name);
734 r = LY_EVALID;
735 }
736 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
737
738 /* parse "action", if any */
739 r = lydxml_envelope(xmlctx, "action", "urn:ietf:params:xml:ns:yang:1", 0, &child);
740 if (r == LY_SUCCESS) {
741 /* insert */
742 lyd_insert_node(*envp, NULL, child);
743
744 /* NETCONF action */
745 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_ACTION;
746 *close_elem = 2;
747 } else if (r == LY_ENOT) {
748 /* NETCONF RPC */
749 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_RPC;
750 *close_elem = 1;
751 } else {
752 rc = r;
753 goto cleanup;
754 }
755
756cleanup:
757 if (rc) {
758 lyd_free_tree(*envp);
759 *envp = NULL;
760 }
761 return rc;
762}
763
764/**
765 * @brief Parse all expected non-data XML elements of a NETCONF notification message.
766 *
767 * @param[in] xmlctx XML parser context.
768 * @param[out] evnp Parsed envelope(s) (opaque node).
769 * @param[out] int_opts Internal options for parsing the rest of YANG data.
770 * @param[out] close_elem Number of parsed opened elements that need to be closed.
771 * @return LY_SUCCESS on success.
772 * @return LY_ERR value on error.
773 */
774static LY_ERR
775lydxml_env_netconf_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
776{
777 LY_ERR rc = LY_SUCCESS, r;
778 struct lyd_node *child;
779
780 assert(envp && !*envp);
781
782 /* parse "notification" */
783 r = lydxml_envelope(xmlctx, "notification", "urn:ietf:params:xml:ns:netconf:notification:1.0", 0, envp);
784 if (r == LY_ENOT) {
785 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"notification\".", xmlctx->name_len,
786 xmlctx->name);
787 r = LY_EVALID;
788 }
789 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
790
791 /* parse "eventTime" */
792 r = lydxml_envelope(xmlctx, "eventTime", "urn:ietf:params:xml:ns:netconf:notification:1.0", 1, &child);
793 if (r == LY_ENOT) {
794 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"eventTime\".", xmlctx->name_len,
795 xmlctx->name);
796 r = LY_EVALID;
797 }
798 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
799
800 /* insert */
801 lyd_insert_node(*envp, NULL, child);
802
803 /* validate value */
804 /* TODO validate child->value as yang:date-and-time */
805
806 /* finish child parsing */
Michal Vaskoa8edff02020-03-27 14:47:01 +0100807 if (xmlctx->status != LYXML_ELEM_CLOSE) {
808 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoe0665742021-02-11 11:08:44 +0100809 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"eventTime\".",
Michal Vasko69730152020-10-09 16:30:07 +0200810 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100811 rc = LY_EVALID;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100812 goto cleanup;
813 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100814 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
815
816 /* NETCONF notification */
817 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_NOTIF;
818 *close_elem = 1;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100819
820cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +0100821 if (rc) {
Michal Vaskoa8edff02020-03-27 14:47:01 +0100822 lyd_free_tree(*envp);
Michal Vaskoe0665742021-02-11 11:08:44 +0100823 *envp = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100824 }
Michal Vaskoe0665742021-02-11 11:08:44 +0100825 return rc;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100826}
Michal Vasko79135ae2020-12-16 10:08:35 +0100827
Michal Vaskoe0665742021-02-11 11:08:44 +0100828/**
829 * @brief Parse an XML element as an opaque node subtree.
830 *
831 * @param[in] xmlctx XML parser context.
832 * @param[in] parent Parent to append nodes to.
833 * @return LY_ERR value.
834 */
835static LY_ERR
836lydxml_opaq_r(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
Michal Vaskoa8edff02020-03-27 14:47:01 +0100837{
Michal Vaskoe0665742021-02-11 11:08:44 +0100838 LY_ERR rc = LY_SUCCESS;
839 const struct lyxml_ns *ns;
840 struct lyd_attr *attr = NULL;
841 struct lyd_node *child = NULL;
842 const char *name, *prefix;
843 size_t name_len, prefix_len;
Michal Vaskoa8edff02020-03-27 14:47:01 +0100844
Michal Vaskoe0665742021-02-11 11:08:44 +0100845 assert(xmlctx->status == LYXML_ELEMENT);
Michal Vaskoa8edff02020-03-27 14:47:01 +0100846
Michal Vaskoe0665742021-02-11 11:08:44 +0100847 name = xmlctx->name;
848 name_len = xmlctx->name_len;
849 prefix = xmlctx->prefix;
850 prefix_len = xmlctx->prefix_len;
851 ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
852 if (!ns) {
853 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
854 return LY_EVALID;
855 }
Michal Vaskoa8edff02020-03-27 14:47:01 +0100856
Michal Vaskoe0665742021-02-11 11:08:44 +0100857 LY_CHECK_RET(lyxml_ctx_next(xmlctx));
Michal Vaskoa8edff02020-03-27 14:47:01 +0100858
Michal Vaskoe0665742021-02-11 11:08:44 +0100859 /* create attributes */
860 if (xmlctx->status == LYXML_ATTRIBUTE) {
861 LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
862 }
863
864 /* create node */
865 assert(xmlctx->status == LYXML_ELEM_CONTENT);
866 rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
867 xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_PREF_XML, NULL, 0, &child);
868 LY_CHECK_GOTO(rc, cleanup);
869
870 /* assign atributes */
871 ((struct lyd_node_opaq *)child)->attr = attr;
872 attr = NULL;
873
874 /* parser next element */
875 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
876
877 /* parse all the descendants */
878 while (xmlctx->status == LYXML_ELEMENT) {
879 rc = lydxml_opaq_r(xmlctx, child);
880 LY_CHECK_GOTO(rc, cleanup);
881 }
882
883 /* insert */
884 lyd_insert_node(parent, NULL, child);
885
886cleanup:
887 lyd_free_attr_siblings(xmlctx->ctx, attr);
888 if (rc) {
889 lyd_free_tree(child);
890 }
891 return rc;
892}
893
894/**
895 * @brief Parse all expected non-data XML elements of the error-info element in NETCONF rpc-reply message.
896 *
897 * @param[in] xmlctx XML parser context.
898 * @param[in] parent Parent to append nodes to.
899 * @return LY_ERR value.
900 */
901static LY_ERR
902lydxml_env_netconf_rpc_reply_error_info(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
903{
904 LY_ERR r;
905 struct lyd_node *child, *iter;
906 const struct lyxml_ns *ns;
907 ly_bool no_dup;
908
909 /* there must be some child */
910 if (xmlctx->status == LYXML_ELEM_CLOSE) {
911 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"error-info\".");
912 return LY_EVALID;
913 }
914
915 while (xmlctx->status == LYXML_ELEMENT) {
916 child = NULL;
917
918 /*
919 * session-id
920 */
921 r = lydxml_envelope(xmlctx, "session-id", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
922 if (r == LY_SUCCESS) {
923 no_dup = 1;
924 goto check_child;
925 } else if (r != LY_ENOT) {
926 goto error;
927 }
928
929 /*
930 * bad-attribute
931 */
932 r = lydxml_envelope(xmlctx, "bad-attribute", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
933 if (r == LY_SUCCESS) {
934 no_dup = 1;
935 goto check_child;
936 } else if (r != LY_ENOT) {
937 goto error;
938 }
939
940 /*
941 * bad-element
942 */
943 r = lydxml_envelope(xmlctx, "bad-element", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
944 if (r == LY_SUCCESS) {
945 no_dup = 1;
946 goto check_child;
947 } else if (r != LY_ENOT) {
948 goto error;
949 }
950
951 /*
952 * bad-namespace
953 */
954 r = lydxml_envelope(xmlctx, "bad-namespace", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
955 if (r == LY_SUCCESS) {
956 no_dup = 1;
957 goto check_child;
958 } else if (r != LY_ENOT) {
959 goto error;
960 }
961
962 if (r == LY_ENOT) {
963 assert(xmlctx->status == LYXML_ELEMENT);
964
965 /* learn namespace */
966 ns = lyxml_ns_get(&xmlctx->ns, xmlctx->prefix, xmlctx->prefix_len);
967 if (!ns) {
968 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", xmlctx->prefix_len, xmlctx->prefix);
969 r = LY_EVALID;
970 goto error;
971 } else if (!strcmp(ns->uri, "urn:ietf:params:xml:ns:netconf:base:1.0")) {
972 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
Radek Krejci53875452021-02-16 13:44:51 +0100973 xmlctx->name_len, xmlctx->name);
Michal Vaskoe0665742021-02-11 11:08:44 +0100974 r = LY_EVALID;
975 goto error;
976 }
977
978 /* custom elements */
979 r = lydxml_opaq_r(xmlctx, parent);
980 LY_CHECK_GOTO(r, error);
981
982 no_dup = 0;
983 }
984
985check_child:
986 /* check for duplicates */
987 if (no_dup) {
988 LY_LIST_FOR(lyd_child(parent), iter) {
989 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
990 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
991 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"error-info\".",
992 ((struct lyd_node_opaq *)child)->name.name);
993 r = LY_EVALID;
994 goto error;
995 }
996 }
997 }
998
999 /* finish child parsing */
1000 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1001 assert(xmlctx->status == LYXML_ELEMENT);
1002 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"error-info\".",
1003 xmlctx->name_len, xmlctx->name);
1004 r = LY_EVALID;
1005 goto error;
1006 }
1007 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1008
1009 /* insert */
1010 lyd_insert_node(parent, NULL, child);
1011 }
1012
1013 return LY_SUCCESS;
1014
1015error:
1016 lyd_free_tree(child);
1017 return r;
1018}
1019
1020/**
1021 * @brief Parse all expected non-data XML elements of the rpc-error element in NETCONF rpc-reply message.
1022 *
1023 * @param[in] xmlctx XML parser context.
1024 * @param[in] parent Parent to append nodes to.
1025 * @return LY_ERR value.
1026 */
1027static LY_ERR
1028lydxml_env_netconf_rpc_reply_error(struct lyxml_ctx *xmlctx, struct lyd_node *parent)
1029{
1030 LY_ERR r;
1031 struct lyd_node *child, *iter;
1032 const char *val;
1033 ly_bool no_dup;
1034
1035 /* there must be some child */
1036 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1037 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-error\".");
1038 return LY_EVALID;
1039 }
1040
1041 while (xmlctx->status == LYXML_ELEMENT) {
1042 child = NULL;
1043
1044 /*
1045 * error-type
1046 */
1047 r = lydxml_envelope(xmlctx, "error-type", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1048 if (r == LY_SUCCESS) {
1049 val = ((struct lyd_node_opaq *)child)->value;
1050 if (strcmp(val, "transport") && strcmp(val, "rpc") && strcmp(val, "protocol") && strcmp(val, "application")) {
1051 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1052 ((struct lyd_node_opaq *)child)->name.name);
1053 r = LY_EVALID;
1054 goto error;
1055 }
1056
1057 no_dup = 1;
1058 goto check_child;
1059 } else if (r != LY_ENOT) {
1060 goto error;
1061 }
1062
1063 /*
1064 * error-tag
1065 */
1066 r = lydxml_envelope(xmlctx, "error-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1067 if (r == LY_SUCCESS) {
1068 val = ((struct lyd_node_opaq *)child)->value;
1069 if (strcmp(val, "in-use") && strcmp(val, "invalid-value") && strcmp(val, "too-big") &&
1070 strcmp(val, "missing-attribute") && strcmp(val, "bad-attribute") &&
1071 strcmp(val, "unknown-attribute") && strcmp(val, "missing-element") && strcmp(val, "bad-element") &&
1072 strcmp(val, "unknown-element") && strcmp(val, "unknown-namespace") && strcmp(val, "access-denied") &&
1073 strcmp(val, "lock-denied") && strcmp(val, "resource-denied") && strcmp(val, "rollback-failed") &&
1074 strcmp(val, "data-exists") && strcmp(val, "data-missing") && strcmp(val, "operation-not-supported") &&
1075 strcmp(val, "operation-failed") && strcmp(val, "malformed-message")) {
1076 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1077 ((struct lyd_node_opaq *)child)->name.name);
1078 r = LY_EVALID;
1079 goto error;
1080 }
1081
1082 no_dup = 1;
1083 goto check_child;
1084 } else if (r != LY_ENOT) {
1085 goto error;
1086 }
1087
1088 /*
1089 * error-severity
1090 */
1091 r = lydxml_envelope(xmlctx, "error-severity", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1092 if (r == LY_SUCCESS) {
1093 val = ((struct lyd_node_opaq *)child)->value;
1094 if (strcmp(val, "error") && strcmp(val, "warning")) {
1095 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Invalid value \"%s\" of element \"%s\".", val,
1096 ((struct lyd_node_opaq *)child)->name.name);
1097 r = LY_EVALID;
1098 goto error;
1099 }
1100
1101 no_dup = 1;
1102 goto check_child;
1103 } else if (r != LY_ENOT) {
1104 goto error;
1105 }
1106
1107 /*
1108 * error-app-tag
1109 */
1110 r = lydxml_envelope(xmlctx, "error-app-tag", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1111 if (r == LY_SUCCESS) {
1112 no_dup = 1;
1113 goto check_child;
1114 } else if (r != LY_ENOT) {
1115 goto error;
1116 }
1117
1118 /*
1119 * error-path
1120 */
1121 r = lydxml_envelope(xmlctx, "error-path", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1122 if (r == LY_SUCCESS) {
1123 no_dup = 1;
1124 goto check_child;
1125 } else if (r != LY_ENOT) {
1126 goto error;
1127 }
1128
1129 /*
1130 * error-message
1131 */
1132 r = lydxml_envelope(xmlctx, "error-message", "urn:ietf:params:xml:ns:netconf:base:1.0", 1, &child);
1133 if (r == LY_SUCCESS) {
1134 no_dup = 1;
1135 goto check_child;
1136 } else if (r != LY_ENOT) {
1137 goto error;
1138 }
1139
1140 /* error-info */
1141 r = lydxml_envelope(xmlctx, "error-info", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1142 if (r == LY_SUCCESS) {
1143 /* parse all the descendants */
1144 LY_CHECK_GOTO(r = lydxml_env_netconf_rpc_reply_error_info(xmlctx, child), error);
1145
1146 no_dup = 0;
1147 goto check_child;
1148 } else if (r != LY_ENOT) {
1149 goto error;
1150 }
1151
1152 if (r == LY_ENOT) {
1153 assert(xmlctx->status == LYXML_ELEMENT);
1154 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1155 xmlctx->name_len, xmlctx->name);
1156 r = LY_EVALID;
1157 goto error;
1158 }
1159
1160check_child:
1161 /* check for duplicates */
1162 if (no_dup) {
1163 LY_LIST_FOR(lyd_child(parent), iter) {
1164 if ((((struct lyd_node_opaq *)iter)->name.name == ((struct lyd_node_opaq *)child)->name.name) &&
1165 (((struct lyd_node_opaq *)iter)->name.module_ns == ((struct lyd_node_opaq *)child)->name.module_ns)) {
1166 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Duplicate element \"%s\" in \"rpc-error\".",
1167 ((struct lyd_node_opaq *)child)->name.name);
1168 r = LY_EVALID;
1169 goto error;
1170 }
1171 }
1172 }
1173
1174 /* finish child parsing */
1175 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1176 assert(xmlctx->status == LYXML_ELEMENT);
1177 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"rpc-error\".",
1178 xmlctx->name_len, xmlctx->name);
1179 r = LY_EVALID;
1180 goto error;
1181 }
1182 LY_CHECK_GOTO(r = lyxml_ctx_next(xmlctx), error);
1183
1184 /* insert */
1185 lyd_insert_node(parent, NULL, child);
1186 }
1187
1188 return LY_SUCCESS;
1189
1190error:
1191 lyd_free_tree(child);
1192 return r;
1193}
1194
1195/**
1196 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply message.
1197 *
1198 * @param[in] xmlctx XML parser context.
1199 * @param[out] evnp Parsed envelope(s) (opaque node).
1200 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1201 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1202 * @return LY_SUCCESS on success.
1203 * @return LY_ERR value on error.
1204 */
1205static LY_ERR
1206lydxml_env_netconf_reply(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts, uint32_t *close_elem)
1207{
1208 LY_ERR rc = LY_SUCCESS, r;
1209 struct lyd_node *child = NULL;
1210 const char *parsed_elem = NULL;
1211
1212 assert(envp && !*envp);
1213
1214 /* parse "rpc-reply" */
1215 r = lydxml_envelope(xmlctx, "rpc-reply", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, envp);
1216 if (r == LY_ENOT) {
1217 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"rpc-reply\".", xmlctx->name_len,
1218 xmlctx->name);
1219 r = LY_EVALID;
1220 }
1221 LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
1222
1223 /* there must be some child */
1224 if (xmlctx->status == LYXML_ELEM_CLOSE) {
1225 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Missing child elements of \"rpc-reply\".");
1226 rc = LY_EVALID;
Michal Vaskocf770e22020-08-12 13:21:43 +02001227 goto cleanup;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001228 }
1229
Michal Vaskoe0665742021-02-11 11:08:44 +01001230 /* try to parse "ok" */
1231 r = lydxml_envelope(xmlctx, "ok", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1232 if (r == LY_SUCCESS) {
1233 /* insert */
1234 lyd_insert_node(*envp, NULL, child);
1235
1236 /* finish child parsing */
1237 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1238 assert(xmlctx->status == LYXML_ELEMENT);
1239 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\" of \"ok\".",
1240 xmlctx->name_len, xmlctx->name);
1241 rc = LY_EVALID;
1242 goto cleanup;
1243 }
1244 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1245
1246 /* success */
1247 parsed_elem = "ok";
1248 goto finish;
1249 } else if (r != LY_ENOT) {
1250 rc = r;
1251 goto cleanup;
Michal Vasko2552ea32020-12-08 15:32:34 +01001252 }
1253
Michal Vaskoe0665742021-02-11 11:08:44 +01001254 /* try to parse all "rpc-error" elements */
1255 while (xmlctx->status == LYXML_ELEMENT) {
1256 r = lydxml_envelope(xmlctx, "rpc-error", "urn:ietf:params:xml:ns:netconf:base:1.0", 0, &child);
1257 if (r == LY_ENOT) {
1258 break;
1259 } else if (r) {
1260 rc = r;
1261 goto cleanup;
1262 }
1263
1264 /* insert */
1265 lyd_insert_node(*envp, NULL, child);
1266
1267 /* parse all children of "rpc-error" */
1268 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc_reply_error(xmlctx, child), cleanup);
1269
1270 /* finish child parsing */
1271 assert(xmlctx->status == LYXML_ELEM_CLOSE);
1272 LY_CHECK_GOTO(rc = lyxml_ctx_next(xmlctx), cleanup);
1273
1274 parsed_elem = "rpc-error";
Michal Vasko2552ea32020-12-08 15:32:34 +01001275 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001276
1277finish:
1278 if (parsed_elem) {
1279 /* NETCONF rpc-reply with no data */
1280 if (xmlctx->status != LYXML_ELEM_CLOSE) {
1281 assert(xmlctx->status == LYXML_ELEMENT);
1282 LOGVAL(xmlctx->ctx, LYVE_SYNTAX, "Unexpected sibling element \"%.*s\" of \"%s\".",
1283 xmlctx->name_len, xmlctx->name, parsed_elem);
1284 rc = LY_EVALID;
1285 goto cleanup;
1286 }
1287 }
1288
1289 /* NETCONF rpc-reply */
1290 *int_opts = LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_REPLY;
1291 *close_elem = 1;
1292
1293cleanup:
1294 if (rc) {
1295 lyd_free_tree(*envp);
1296 *envp = NULL;
1297 }
1298 return rc;
1299}
1300
1301/**
1302 * @brief Parse all expected non-data XML elements of a NETCONF rpc-reply or notification message.
1303 *
1304 * @param[in] xmlctx XML parser context.
1305 * @param[out] evnp Parsed envelope(s) (opaque node).
1306 * @param[out] int_opts Internal options for parsing the rest of YANG data.
1307 * @param[out] close_elem Number of parsed opened elements that need to be closed.
1308 * @param[out] parent_p Parent to append to the rest of YANG data, may be unset.
1309 * @return LY_SUCCESS on success.
1310 * @return LY_ERR value on error.
1311 */
1312static LY_ERR
1313lydxml_env_netconf_reply_or_notif(struct lyxml_ctx *xmlctx, struct lyd_node **envp, uint32_t *int_opts,
1314 uint32_t *close_elem, struct lyd_node **parent_p)
1315{
1316 /* is it a "rpc-reply" or a "notification"? */
1317 assert(xmlctx->status == LYXML_ELEMENT);
1318 if (!ly_strncmp("rpc-reply", xmlctx->name, xmlctx->name_len)) {
1319 LY_CHECK_RET(lydxml_env_netconf_reply(xmlctx, envp, int_opts, close_elem));
1320 } else if (!ly_strncmp("notification", xmlctx->name, xmlctx->name_len)) {
1321 LY_CHECK_RET(lydxml_env_netconf_notif(xmlctx, envp, int_opts, close_elem));
1322
1323 /* unset parent, the notification starts from top-level */
1324 *parent_p = NULL;
1325 } else {
1326 LOGVAL(xmlctx->ctx, LYVE_REFERENCE, "Unexpected element \"%.*s\" instead of \"rpc-reply\" or \"notification\".",
1327 xmlctx->name_len, xmlctx->name);
1328 return LY_EVALID;
1329 }
1330
1331 return LY_SUCCESS;
Michal Vasko2552ea32020-12-08 15:32:34 +01001332}
1333
1334LY_ERR
Michal Vaskoe0665742021-02-11 11:08:44 +01001335lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_in *in,
1336 uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type, struct lyd_node **envp, struct ly_set *parsed,
1337 struct lyd_ctx **lydctx_p)
Michal Vasko2552ea32020-12-08 15:32:34 +01001338{
Michal Vaskoe0665742021-02-11 11:08:44 +01001339 LY_ERR rc = LY_SUCCESS;
1340 struct lyd_xml_ctx *lydctx;
1341 uint32_t i, int_opts, close_elem = 0;
1342 ly_bool parsed_data_nodes = 0;
Michal Vasko2552ea32020-12-08 15:32:34 +01001343
Michal Vaskoe0665742021-02-11 11:08:44 +01001344 assert(ctx && in && lydctx_p);
1345 assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
1346 assert(!(val_opts & ~LYD_VALIDATE_OPTS_MASK));
Michal Vasko2552ea32020-12-08 15:32:34 +01001347
Michal Vaskoe0665742021-02-11 11:08:44 +01001348 /* init context */
1349 lydctx = calloc(1, sizeof *lydctx);
1350 LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
1351 LY_CHECK_GOTO(rc = lyxml_ctx_new(ctx, in, &lydctx->xmlctx), cleanup);
1352 lydctx->parse_opts = parse_opts;
1353 lydctx->val_opts = val_opts;
1354 lydctx->free = lyd_xml_ctx_free;
Michal Vasko2552ea32020-12-08 15:32:34 +01001355
Michal Vaskoe0665742021-02-11 11:08:44 +01001356 switch (data_type) {
1357 case LYD_TYPE_YANG_DATA:
1358 int_opts = LYD_INTOPT_WITH_SIBLINGS;
1359 break;
1360 case LYD_TYPE_YANG_RPC:
1361 int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
1362 break;
1363 case LYD_TYPE_YANG_NOTIF:
1364 int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS;
1365 break;
1366 case LYD_TYPE_YANG_REPLY:
1367 int_opts = LYD_INTOPT_REPLY | LYD_INTOPT_NO_SIBLINGS;
1368 break;
1369 case LYD_TYPE_NETCONF_RPC:
1370 assert(!parent);
1371 LY_CHECK_GOTO(rc = lydxml_env_netconf_rpc(lydctx->xmlctx, envp, &int_opts, &close_elem), cleanup);
1372 break;
1373 case LYD_TYPE_NETCONF_REPLY_OR_NOTIF:
1374 assert(parent);
1375 LY_CHECK_GOTO(rc = lydxml_env_netconf_reply_or_notif(lydctx->xmlctx, envp, &int_opts, &close_elem, &parent),
1376 cleanup);
1377 break;
1378 }
1379 lydctx->int_opts = int_opts;
1380
1381 /* find the operation node if it exists already */
1382 LY_CHECK_GOTO(rc = lyd_parser_find_operation(parent, int_opts, &lydctx->op_node), cleanup);
1383
1384 /* parse XML data */
1385 while (lydctx->xmlctx->status == LYXML_ELEMENT) {
1386 LY_CHECK_GOTO(rc = lydxml_subtree_r(lydctx, parent, first_p, parsed), cleanup);
1387 parsed_data_nodes = 1;
1388
1389 if (!(int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
1390 break;
1391 }
Michal Vasko2552ea32020-12-08 15:32:34 +01001392 }
1393
Michal Vaskoe0665742021-02-11 11:08:44 +01001394 /* close all opened elements */
1395 for (i = 0; i < close_elem; ++i) {
1396 if (lydctx->xmlctx->status != LYXML_ELEM_CLOSE) {
1397 assert(lydctx->xmlctx->status == LYXML_ELEMENT);
1398 LOGVAL(lydctx->xmlctx->ctx, LYVE_SYNTAX, "Unexpected child element \"%.*s\".", lydctx->xmlctx->name_len,
1399 lydctx->xmlctx->name);
1400 rc = LY_EVALID;
1401 goto cleanup;
1402 }
1403
1404 LY_CHECK_GOTO(rc = lyxml_ctx_next(lydctx->xmlctx), cleanup);
Michal Vasko4189c0f2020-08-13 09:05:22 +02001405 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001406
1407 /* check final state */
1408 if ((int_opts & LYD_INTOPT_NO_SIBLINGS) && (lydctx->xmlctx->status == LYXML_ELEMENT)) {
1409 LOGVAL(ctx, LYVE_SYNTAX, "Unexpected sibling node.");
1410 rc = LY_EVALID;
1411 goto cleanup;
1412 }
1413 if ((int_opts & (LYD_INTOPT_RPC | LYD_INTOPT_NOTIF | LYD_INTOPT_REPLY)) && !lydctx->op_node) {
1414 LOGVAL(ctx, LYVE_DATA, "Missing the operation node.");
1415 rc = LY_EVALID;
1416 goto cleanup;
1417 }
1418
1419 if (!parsed_data_nodes) {
1420 /* no data nodes were parsed */
1421 lydctx->op_node = NULL;
Michal Vaskoa8edff02020-03-27 14:47:01 +01001422 }
1423
1424cleanup:
Michal Vaskoe0665742021-02-11 11:08:44 +01001425 /* there should be no unres stored if validation should be skipped */
1426 assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
1427 !lydctx->node_when.count));
1428
1429 if (rc) {
1430 lyd_xml_ctx_free((struct lyd_ctx *)lydctx);
1431 } else {
1432 *lydctx_p = (struct lyd_ctx *)lydctx;
1433
1434 /* the XML context is no more needed, freeing it also stops logging line numbers which would be confusing now */
1435 lyxml_ctx_free(lydctx->xmlctx);
1436 lydctx->xmlctx = NULL;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001437 }
Michal Vaskoe0665742021-02-11 11:08:44 +01001438 return rc;
Michal Vasko1ce933a2020-03-30 12:38:22 +02001439}