1 /* $NetBSD: generic.c,v 1.3 2022/04/03 01:10:59 christos Exp $ */
2
3 /* generic.c
4
5 Subroutines that support the generic object. */
6
7 /*
8 * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1999-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Internet Systems Consortium, Inc.
24 * PO Box 360
25 * Newmarket, NH 03857 USA
26 * <info@isc.org>
27 * https://www.isc.org/
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: generic.c,v 1.3 2022/04/03 01:10:59 christos Exp $");
33
34 #include "dhcpd.h"
35
36 #include <omapip/omapip_p.h>
37
OMAPI_OBJECT_ALLOC(omapi_generic,omapi_generic_object_t,omapi_type_generic)38 OMAPI_OBJECT_ALLOC (omapi_generic,
39 omapi_generic_object_t, omapi_type_generic)
40
41 isc_result_t omapi_generic_new (omapi_object_t **gen,
42 const char *file, int line)
43 {
44 /* Backwards compatibility. */
45 return omapi_generic_allocate ((omapi_generic_object_t **)gen,
46 file, line);
47 }
48
omapi_generic_set_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_typed_data_t * value)49 isc_result_t omapi_generic_set_value (omapi_object_t *h,
50 omapi_object_t *id,
51 omapi_data_string_t *name,
52 omapi_typed_data_t *value)
53 {
54 omapi_generic_object_t *g;
55 omapi_value_t *new;
56 omapi_value_t **va;
57 u_int8_t *ca;
58 int vm_new;
59 int i, vfree = -1;
60 isc_result_t status;
61
62 if (h -> type != omapi_type_generic)
63 return DHCP_R_INVALIDARG;
64 g = (omapi_generic_object_t *)h;
65
66 /* See if there's already a value with this name attached to
67 the generic object, and if so, replace the current value
68 with the new one. */
69 for (i = 0; i < g -> nvalues; i++) {
70 if (!g -> values[i])
71 continue;
72
73 if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
74 /* There's an inconsistency here: the standard
75 behaviour of a set_values method when
76 passed a matching name and a null value is
77 to delete the value associated with that
78 name (where possible). In the generic
79 object, we remember the name/null pair,
80 because generic objects are generally used
81 to pass messages around, and this is the
82 way that remote entities delete values from
83 local objects. If the get_value method of
84 a generic object is called for a name that
85 maps to a name/null pair, ISC_R_NOTFOUND is
86 returned. */
87 new = (omapi_value_t *)0;
88 status = (omapi_value_new (&new, MDL));
89 if (status != ISC_R_SUCCESS)
90 return status;
91 omapi_data_string_reference (&new -> name, name, MDL);
92 if (value)
93 omapi_typed_data_reference (&new -> value,
94 value, MDL);
95
96 omapi_value_dereference (&(g -> values [i]), MDL);
97 status = (omapi_value_reference
98 (&(g -> values [i]), new, MDL));
99 omapi_value_dereference (&new, MDL);
100 g -> changed [i] = 1;
101 return status;
102 }
103 /* Notice a free slot if we pass one. */
104 else if (vfree == -1 && !g -> values [i])
105 vfree = i;
106 }
107
108 /* If the name isn't already attached to this object, see if an
109 inner object has it. */
110 if (h -> inner && h -> inner -> type -> set_value) {
111 status = ((*(h -> inner -> type -> set_value))
112 (h -> inner, id, name, value));
113 if (status != ISC_R_NOTFOUND)
114 return status;
115 }
116
117 /* Okay, so it's a value that no inner object knows about, and
118 (implicitly, since the outer object set_value method would
119 have called this object's set_value method) it's an object that
120 no outer object knows about, it's this object's responsibility
121 to remember it - that's what generic objects do. */
122
123 /* Arrange for there to be space for the pointer to the new
124 name/value pair if necessary: */
125 if (vfree == -1) {
126 vfree = g -> nvalues;
127 if (vfree == g -> va_max) {
128 if (g -> va_max)
129 vm_new = 2 * g -> va_max;
130 else
131 vm_new = 10;
132 va = dmalloc (vm_new * sizeof *va, MDL);
133 if (!va)
134 return ISC_R_NOMEMORY;
135 ca = dmalloc (vm_new * sizeof *ca, MDL);
136 if (!ca) {
137 dfree (va, MDL);
138 return ISC_R_NOMEMORY;
139 }
140 if (g -> va_max) {
141 memcpy (va, g -> values,
142 g -> va_max * sizeof *va);
143 memcpy (ca, g -> changed,
144 g -> va_max * sizeof *ca);
145 }
146 memset (va + g -> va_max, 0,
147 (vm_new - g -> va_max) * sizeof *va);
148 memset (ca + g -> va_max, 0,
149 (vm_new - g -> va_max) * sizeof *ca);
150 if (g -> values)
151 dfree (g -> values, MDL);
152 if (g -> changed)
153 dfree (g -> changed, MDL);
154 g -> values = va;
155 g -> changed = ca;
156 g -> va_max = vm_new;
157 }
158 }
159 status = omapi_value_new (&g -> values [vfree], MDL);
160 if (status != ISC_R_SUCCESS)
161 return status;
162 omapi_data_string_reference (&g -> values [vfree] -> name,
163 name, MDL);
164 if (value)
165 omapi_typed_data_reference
166 (&g -> values [vfree] -> value, value, MDL);
167 g -> changed [vfree] = 1;
168 if (vfree == g -> nvalues)
169 g -> nvalues++;
170 return ISC_R_SUCCESS;
171 }
172
omapi_generic_get_value(omapi_object_t * h,omapi_object_t * id,omapi_data_string_t * name,omapi_value_t ** value)173 isc_result_t omapi_generic_get_value (omapi_object_t *h,
174 omapi_object_t *id,
175 omapi_data_string_t *name,
176 omapi_value_t **value)
177 {
178 int i;
179 omapi_generic_object_t *g;
180
181 if (h -> type != omapi_type_generic)
182 return DHCP_R_INVALIDARG;
183 g = (omapi_generic_object_t *)h;
184
185 /* Look up the specified name in our list of objects. */
186 for (i = 0; i < g -> nvalues; i++) {
187 if (!g -> values[i])
188 continue;
189 if (!omapi_data_string_cmp (name, g -> values [i] -> name)) {
190 /* If this is a name/null value pair, this is the
191 same as if there were no value that matched
192 the specified name, so return ISC_R_NOTFOUND. */
193 if (!g -> values [i] -> value)
194 return ISC_R_NOTFOUND;
195 /* Otherwise, return the name/value pair. */
196 return omapi_value_reference (value,
197 g -> values [i], MDL);
198 }
199 }
200
201 if (h -> inner && h -> inner -> type -> get_value)
202 return (*(h -> inner -> type -> get_value))
203 (h -> inner, id, name, value);
204 return ISC_R_NOTFOUND;
205 }
206
omapi_generic_destroy(omapi_object_t * h,const char * file,int line)207 isc_result_t omapi_generic_destroy (omapi_object_t *h,
208 const char *file, int line)
209 {
210 omapi_generic_object_t *g;
211 int i;
212
213 if (h -> type != omapi_type_generic)
214 return ISC_R_UNEXPECTED;
215 g = (omapi_generic_object_t *)h;
216
217 if (g -> values) {
218 for (i = 0; i < g -> nvalues; i++) {
219 if (g -> values [i])
220 omapi_value_dereference (&g -> values [i],
221 file, line);
222 }
223 dfree (g -> values, file, line);
224 dfree (g -> changed, file, line);
225 g -> values = (omapi_value_t **)0;
226 g -> changed = (u_int8_t *)0;
227 g -> va_max = 0;
228 }
229
230 return ISC_R_SUCCESS;
231 }
232
omapi_generic_signal_handler(omapi_object_t * h,const char * name,va_list ap)233 isc_result_t omapi_generic_signal_handler (omapi_object_t *h,
234 const char *name, va_list ap)
235 {
236 if (h -> type != omapi_type_generic)
237 return DHCP_R_INVALIDARG;
238
239 if (h -> inner && h -> inner -> type -> signal_handler)
240 return (*(h -> inner -> type -> signal_handler)) (h -> inner,
241 name, ap);
242 return ISC_R_NOTFOUND;
243 }
244
245 /* Write all the published values associated with the object through the
246 specified connection. */
247
omapi_generic_stuff_values(omapi_object_t * c,omapi_object_t * id,omapi_object_t * g)248 isc_result_t omapi_generic_stuff_values (omapi_object_t *c,
249 omapi_object_t *id,
250 omapi_object_t *g)
251 {
252 omapi_generic_object_t *src;
253 int i;
254 isc_result_t status;
255
256 if (g -> type != omapi_type_generic)
257 return DHCP_R_INVALIDARG;
258 src = (omapi_generic_object_t *)g;
259
260 for (i = 0; i < src -> nvalues; i++) {
261 if (src -> values [i] && src -> values [i] -> name -> len &&
262 src -> changed [i]) {
263 status = (omapi_connection_put_uint16
264 (c, src -> values [i] -> name -> len));
265 if (status != ISC_R_SUCCESS)
266 return status;
267 status = (omapi_connection_copyin
268 (c, src -> values [i] -> name -> value,
269 src -> values [i] -> name -> len));
270 if (status != ISC_R_SUCCESS)
271 return status;
272
273 status = (omapi_connection_write_typed_data
274 (c, src -> values [i] -> value));
275 if (status != ISC_R_SUCCESS)
276 return status;
277 }
278 }
279
280 if (g -> inner && g -> inner -> type -> stuff_values)
281 return (*(g -> inner -> type -> stuff_values)) (c, id,
282 g -> inner);
283 return ISC_R_SUCCESS;
284 }
285
286 /* Clear the changed flags on the object. This has the effect that if
287 generic_stuff is called, any attributes that still have a cleared changed
288 flag aren't sent to the peer. This also deletes any values that are
289 null, presuming that these have now been properly handled. */
290
omapi_generic_clear_flags(omapi_object_t * o)291 isc_result_t omapi_generic_clear_flags (omapi_object_t *o)
292 {
293 int i;
294 omapi_generic_object_t *g;
295
296 if (o -> type != omapi_type_generic)
297 return DHCP_R_INVALIDARG;
298 g = (omapi_generic_object_t *)o;
299
300 for (i = 0; i < g -> nvalues; i++) {
301 g -> changed [i] = 0;
302 if (g -> values [i] &&
303 !g -> values [i] -> value)
304 omapi_value_dereference (&g -> values [i], MDL);
305 }
306 return ISC_R_SUCCESS;
307 }
308