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 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 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 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 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 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 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 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