Home | History | Annotate | Line # | Download | only in omapip
      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 (at) 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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