1 /**
2 * @file yangdata.c
3 * @author Pavol Vican <vican.pavol@gmail.com>
4 * @brief libyang extension plugin - YANG DATA (RFC 8040)
5 *
6 * Copyright (c) 2018 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
15 #ifdef __GNUC__
16 # define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
17 #else
18 # define UNUSED(x) UNUSED_ ## x
19 #endif
20
21 #include <stdlib.h>
22 #include "../extensions.h"
23
24 /**
25 * @brief Storage for ID used to check plugin API version compatibility.
26 */
27 LYEXT_VERSION_CHECK
28
29 int check_node(struct lys_node *node);
30
31 /**
32 * @brief Callback to check that the yang-data can be instantiated inside the provided node
33 *
34 * @param[in] parent The parent of the instantiated extension.
35 * @param[in] parent_type The type of the structure provided as \p parent.
36 * @param[in] substmt_type libyang does not store all the extension instances in the structures where they are
37 * instantiated in the module. In some cases (see #LYEXT_SUBSTMT) they are stored in parent
38 * structure and marked with flag to know in which substatement of the parent the extension
39 * was originally instantiated.
40 * @return 0 - ok
41 * 1 - error
42 */
yang_data_position(const void * UNUSED (parent),LYEXT_PAR parent_type,LYEXT_SUBSTMT UNUSED (substmt_type))43 int yang_data_position(const void * UNUSED(parent), LYEXT_PAR parent_type, LYEXT_SUBSTMT UNUSED(substmt_type))
44 {
45 /* yang-data can appear only at the top level of a YANG module or submodule */
46 if (parent_type == LYEXT_PAR_MODULE) {
47 return 0;
48 } else {
49 return 1;
50 }
51 }
52
53 /* return values - 0 - OK
54 * 1 - Something wrong
55 * -1 - Absolute wrong
56 */
check_choice(struct lys_node * root)57 int check_choice(struct lys_node *root) {
58 struct lys_node *node, *next;
59 int result = 1, tmp_result;
60
61 LY_TREE_FOR_SAFE(root->child, next, node) {
62 tmp_result = (node->nodetype == LYS_CASE) ? check_node(node->child) : check_node(node);
63 if (tmp_result == -1) {
64 return -1;
65 } else if (tmp_result == 0) {
66 result = 0;
67 }
68 }
69
70 return result;
71 }
72
73 /* return values - 0 - OK
74 * 1 - Something wrong
75 * -1 - Absolute wrong
76 */
check_node(struct lys_node * node)77 int check_node(struct lys_node *node) {
78
79 int result = 0;
80
81 if (node == NULL) {
82 return 1;
83 }
84
85 /* check nodes and find only one container */
86 if (node->nodetype == LYS_CHOICE) {
87 result = check_choice(node);
88 } else if (node->nodetype == LYS_USES) {
89 result = check_node(((struct lys_node_uses*)node)->grp->child);
90 } else if (node->nodetype != LYS_CONTAINER || (node->next != NULL || node->prev != node)) {
91 result = -1;
92 }
93
94 return result;
95 }
96
97
remove_iffeature(struct lys_iffeature ** iffeature,uint8_t * iffeature_size,struct ly_ctx * ctx)98 void remove_iffeature(struct lys_iffeature **iffeature, uint8_t *iffeature_size, struct ly_ctx *ctx) {
99
100 lys_iffeature_free(ctx, *iffeature, *iffeature_size, 0, NULL);
101 *iffeature_size = 0;
102 *iffeature = NULL;
103 }
104
remove_iffeature_type(struct lys_type * type,struct ly_ctx * ctx)105 void remove_iffeature_type(struct lys_type *type, struct ly_ctx *ctx) {
106 unsigned int i;
107
108 if (type->base == LY_TYPE_ENUM) {
109 for (i = 0; i < type->info.enums.count; ++i) {
110 remove_iffeature(&type->info.enums.enm[i].iffeature, &type->info.enums.enm[i].iffeature_size, ctx);
111 }
112 } else if (type->base == LY_TYPE_BITS) {
113 for (i = 0; i < type->info.bits.count; ++i) {
114 remove_iffeature(&type->info.bits.bit[i].iffeature, &type->info.bits.bit[i].iffeature_size, ctx);
115 }
116 }
117 }
118
119 /* fix schema - ignore config flag, iffeature */
fix_schema(struct lys_node * root,struct ly_ctx * ctx)120 void fix_schema(struct lys_node *root, struct ly_ctx *ctx) {
121 struct lys_node *node, *next;
122 struct lys_node_container *cont;
123 struct lys_node_rpc_action *action;
124 struct lys_node_grp *grp;
125 struct lys_node_uses *uses;
126 int i;
127
128 LY_TREE_DFS_BEGIN(root, next, node) {
129 /* ignore config flag */
130 node->flags = node->flags & (~(LYS_CONFIG_MASK | LYS_CONFIG_SET));
131 remove_iffeature(&node->iffeature, &node->iffeature_size, ctx);
132 switch (node->nodetype) {
133 case LYS_CONTAINER:
134 cont = (struct lys_node_container *)node;
135 for (i = 0; i < cont->tpdf_size; ++i) {
136 remove_iffeature_type(&cont->tpdf[i].type, ctx);
137 }
138 break;
139 case LYS_LEAF:
140 remove_iffeature_type(&((struct lys_node_leaf *)node)->type, ctx);
141 break;
142 case LYS_LEAFLIST:
143 remove_iffeature_type(&((struct lys_node_leaflist *)node)->type, ctx);
144 break;
145 case LYS_ACTION:
146 case LYS_NOTIF:
147 action = (struct lys_node_rpc_action *)node;
148 for (i = 0; i < action->tpdf_size; ++i) {
149 remove_iffeature_type(&action->tpdf[i].type, ctx);
150 }
151 break;
152 case LYS_GROUPING:
153 grp = (struct lys_node_grp *)node;
154 for (i = 0; i < grp->tpdf_size; ++i) {
155 remove_iffeature_type(&grp->tpdf[i].type, ctx);
156 }
157 break;
158 case LYS_USES:
159 uses = (struct lys_node_uses *)node;
160 for (i = 0; i < uses->augment_size; ++i) {
161 remove_iffeature(&uses->augment[i].iffeature, &uses->augment[i].iffeature_size, ctx);
162 fix_schema(uses->augment[i].child, ctx);
163 }
164 for (i = 0; i < uses->refine_size; ++i) {
165 remove_iffeature(&uses->refine[i].iffeature, &uses->refine[i].iffeature_size, ctx);
166 }
167 break;
168 default:
169 break;
170 }
171 LY_TREE_DFS_END(root, next, node)
172 }
173 }
174
yang_data_result(struct lys_ext_instance * ext)175 int yang_data_result(struct lys_ext_instance *ext) {
176 struct lys_node **root;
177
178 root = lys_ext_complex_get_substmt(LY_STMT_CONTAINER, (struct lys_ext_instance_complex *)ext, NULL);
179 if (!root || !(*root) || (*root)->next != NULL || check_node(*root)) {
180 return 1;
181 }
182
183 fix_schema(*root, ext->def->module->ctx);
184 return 0;
185 }
186
187 struct lyext_substmt yang_data_substmt[] = {
188 {LY_STMT_USES, 0, LY_STMT_CARD_OPT},
189 {LY_STMT_CONTAINER, 0, LY_STMT_CARD_OPT},
190 {LY_STMT_CHOICE, 0, LY_STMT_CARD_OPT},
191 {0, 0, 0} /* terminating item */
192 };
193
194 /**
195 * @brief Plugin for the RFC 8040 restconf extension
196 */
197 struct lyext_plugin_complex yang_data = {
198 .type = LYEXT_COMPLEX,
199 .flags = 0,
200 .check_position = &yang_data_position,
201 .check_result = &yang_data_result,
202 .check_inherit = NULL,
203 .valid_data = NULL,
204 /* specification of allowed substatements of the extension instance */
205 .substmt = yang_data_substmt,
206
207 /* final size of the extension instance structure with the space for storing the substatements */
208 .instance_size = (sizeof(struct lys_ext_instance_complex) - 1) + 2 * sizeof(void*)
209 };
210
211 /**
212 * @brief list of all extension plugins implemented here
213 *
214 * MANDATORY object for all libyang extension plugins, the name must match the <name>.so
215 */
216 struct lyext_plugin_list yangdata[] = {
217 {"ietf-restconf", "2017-01-26", "yang-data", (struct lyext_plugin*)&yang_data},
218 {NULL, NULL, NULL, NULL} /* terminating item */
219 };
220