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