xref: /netbsd-src/external/mpl/dhcp/dist/omapip/generic.c (revision f407d9293b6650aa8c33d6a995f797bb6aaefd90)
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