npf_var.c revision 1.7 1 /* $NetBSD: npf_var.c,v 1.7 2012/11/15 22:20:27 rmind Exp $ */
2
3 /*-
4 * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: npf_var.c,v 1.7 2012/11/15 22:20:27 rmind Exp $");
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #define _NPFVAR_PRIVATE
40 #include "npfctl.h"
41
42 typedef struct npf_element {
43 void * e_data;
44 int e_type;
45 struct npf_element *e_next;
46 } npf_element_t;
47
48 struct npfvar {
49 char * v_key;
50 npf_element_t * v_elements;
51 npf_element_t * v_last;
52 int v_type;
53 size_t v_count;
54 void * v_next;
55 };
56
57 static npfvar_t * var_list = NULL;
58 static size_t var_num = 0;
59
60 npfvar_t *
61 npfvar_create(const char *name)
62 {
63 npfvar_t *vp = ecalloc(1, sizeof(*vp));
64 vp->v_key = estrdup(name);
65 var_num++;
66 return vp;
67 }
68
69 npfvar_t *
70 npfvar_lookup(const char *key)
71 {
72 for (npfvar_t *it = var_list; it != NULL; it = it->v_next)
73 if (strcmp(it->v_key, key) == 0)
74 return it;
75 return NULL;
76 }
77
78 const char *
79 npfvar_type(size_t t)
80 {
81 if (t >= __arraycount(npfvar_types)) {
82 return "unknown";
83 }
84 return npfvar_types[t];
85 }
86
87 void
88 npfvar_add(npfvar_t *vp)
89 {
90 vp->v_next = var_list;
91 var_list = vp;
92 }
93
94 npfvar_t *
95 npfvar_add_element(npfvar_t *vp, int type, const void *data, size_t len)
96 {
97 npf_element_t *el;
98
99 if (vp->v_count == 0) {
100 vp->v_type = type;
101 } else if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) {
102 yyerror("element type '%s' does not match variable type '%s'",
103 npfvar_type(type), npfvar_type(vp->v_type));
104 return NULL;
105 }
106 vp->v_count++;
107 el = ecalloc(1, sizeof(*el));
108 el->e_data = ecalloc(1, len);
109 el->e_type = type;
110 memcpy(el->e_data, data, len);
111
112 /* Preserve order of insertion. */
113 if (vp->v_elements == NULL) {
114 vp->v_elements = el;
115 } else {
116 vp->v_last->e_next = el;
117 }
118 vp->v_last = el;
119 return vp;
120 }
121
122 npfvar_t *
123 npfvar_add_elements(npfvar_t *vp, npfvar_t *vp2)
124 {
125 if (vp2 == NULL)
126 return vp;
127 if (vp == NULL)
128 return vp2;
129
130 if (vp->v_elements == NULL) {
131 if (vp2->v_elements) {
132 vp->v_type = vp2->v_type;
133 vp->v_elements = vp2->v_elements;
134 }
135 } else if (vp2->v_elements) {
136 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(vp2->v_type)) {
137 yyerror("variable '%s' type '%s' does not match "
138 "variable '%s' type '%s'", vp->v_key,
139 npfvar_type(vp->v_type),
140 vp2->v_key, npfvar_type(vp2->v_type));
141 return NULL;
142 }
143 vp->v_last->e_next = vp2->v_elements;
144 }
145 if (vp2->v_elements) {
146 vp->v_last = vp2->v_last;
147 vp->v_count += vp2->v_count;
148 vp2->v_elements = NULL;
149 vp2->v_count = 0;
150 vp2->v_last = NULL;
151 }
152 npfvar_destroy(vp2);
153 return vp;
154 }
155
156 static void
157 npfvar_free_elements(npf_element_t *el)
158 {
159 if (el == NULL)
160 return;
161 npfvar_free_elements(el->e_next);
162 free(el->e_data);
163 free(el);
164 }
165
166 void
167 npfvar_destroy(npfvar_t *vp)
168 {
169 npfvar_free_elements(vp->v_elements);
170 free(vp->v_key);
171 free(vp);
172 var_num--;
173 }
174
175 char *
176 npfvar_expand_string(const npfvar_t *vp)
177 {
178 return npfvar_get_data(vp, NPFVAR_STRING, 0);
179 }
180
181 size_t
182 npfvar_get_count(const npfvar_t *vp)
183 {
184 return vp ? vp->v_count : 0;
185 }
186
187 static void *
188 npfvar_get_data1(const npfvar_t *vp, int type, size_t idx, size_t level)
189 {
190 npf_element_t *el;
191
192 if (level >= var_num) {
193 yyerror("variable loop for '%s'", vp->v_key);
194 return NULL;
195 }
196
197 if (vp == NULL)
198 return NULL;
199
200 if (NPFVAR_TYPE(vp->v_type) != NPFVAR_TYPE(type)) {
201 yyerror("variable '%s' is of type '%s' not '%s'", vp->v_key,
202 npfvar_type(vp->v_type), npfvar_type(type));
203 return NULL;
204 }
205
206 if (vp->v_count <= idx) {
207 yyerror("variable '%s' has only %zu elements, requested %zu",
208 vp->v_key, vp->v_count, idx);
209 return NULL;
210 }
211
212 el = vp->v_elements;
213 while (idx--) {
214 el = el->e_next;
215 }
216
217 if (vp->v_type == NPFVAR_VAR_ID) {
218 npfvar_t *rvp = npfvar_lookup(el->e_data);
219 return npfvar_get_data1(rvp, type, 0, level + 1);
220 }
221 return el->e_data;
222 }
223
224 static int
225 npfvar_get_type1(const npfvar_t *vp, size_t idx, size_t level)
226 {
227 npf_element_t *el;
228
229 if (level >= var_num) {
230 yyerror("variable loop for '%s'", vp->v_key);
231 return -1;
232 }
233
234 if (vp == NULL)
235 return -1;
236
237 if (vp->v_count <= idx) {
238 yyerror("variable '%s' has only %zu elements, requested %zu",
239 vp->v_key, vp->v_count, idx);
240 return -1;
241 }
242
243 el = vp->v_elements;
244 while (idx--) {
245 el = el->e_next;
246 }
247
248 if (vp->v_type == NPFVAR_VAR_ID) {
249 npfvar_t *rvp = npfvar_lookup(el->e_data);
250 return npfvar_get_type1(rvp, 0, level + 1);
251 }
252 return el->e_type;
253 }
254
255 int
256 npfvar_get_type(const npfvar_t *vp, size_t idx)
257 {
258 return npfvar_get_type1(vp, idx, 0);
259 }
260
261 void *
262 npfvar_get_data(const npfvar_t *vp, int type, size_t idx)
263 {
264 return npfvar_get_data1(vp, type, idx, 0);
265 }
266