Home | History | Annotate | Line # | Download | only in dhcpctl
      1 /*	$NetBSD: dhcpctl.c,v 1.3 2022/04/03 01:10:58 christos Exp $	*/
      2 
      3 /* dhcpctl.c
      4 
      5    Subroutines providing general support for objects. */
      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: dhcpctl.c,v 1.3 2022/04/03 01:10:58 christos Exp $");
     33 
     34 #include "dhcpd.h"
     35 #include <omapip/omapip_p.h>
     36 #include "dhcpctl.h"
     37 #include <sys/time.h>
     38 
     39 /* #define DEBUG_DHCPCTL  1 */
     40 
     41 omapi_object_type_t *dhcpctl_callback_type;
     42 omapi_object_type_t *dhcpctl_remote_type;
     43 
     44 /* dhcpctl_initialize ()
     45 
     46    Must be called before any other dhcpctl function. */
     47 
     48 dhcpctl_status dhcpctl_initialize ()
     49 {
     50 	isc_result_t status;
     51 
     52 	/* Set up the isc and dns library managers */
     53 	status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
     54 				     NULL, NULL);
     55 	if (status != ISC_R_SUCCESS)
     56 		return status;
     57 
     58 	status = omapi_init();
     59 	if (status != ISC_R_SUCCESS)
     60 		return status;
     61 
     62 	status = omapi_object_type_register (&dhcpctl_callback_type,
     63 					     "dhcpctl-callback",
     64 					     dhcpctl_callback_set_value,
     65 					     dhcpctl_callback_get_value,
     66 					     dhcpctl_callback_destroy,
     67 					     dhcpctl_callback_signal_handler,
     68 					     dhcpctl_callback_stuff_values,
     69 					     0, 0, 0, 0, 0, 0,
     70 					     sizeof
     71 					     (dhcpctl_callback_object_t), 0,
     72 					     RC_MISC);
     73 	if (status != ISC_R_SUCCESS)
     74 		return status;
     75 
     76 	status = omapi_object_type_register (&dhcpctl_remote_type,
     77 					     "dhcpctl-remote",
     78 					     dhcpctl_remote_set_value,
     79 					     dhcpctl_remote_get_value,
     80 					     dhcpctl_remote_destroy,
     81 					     dhcpctl_remote_signal_handler,
     82 					     dhcpctl_remote_stuff_values,
     83 					     0, 0, 0, 0, 0, 0,
     84 					     sizeof (dhcpctl_remote_object_t),
     85 					     0, RC_MISC);
     86 	if (status != ISC_R_SUCCESS)
     87 		return status;
     88 
     89 	return ISC_R_SUCCESS;
     90 }
     91 
     92 /* dhcpctl_connect
     93 
     94    synchronous
     95    returns nonzero status code if it didn't connect, zero otherwise
     96    stores connection handle through connection, which can be used
     97    for subsequent access to the specified server.
     98    server_name is the name of the server, and port is the TCP
     99    port on which it is listening.
    100    authinfo is the handle to an object containing authentication
    101    information. */
    102 
    103 dhcpctl_status dhcpctl_connect (dhcpctl_handle *connection,
    104 				const char *server_name, int port,
    105 				dhcpctl_handle authinfo)
    106 {
    107 	isc_result_t status;
    108 #ifdef DEBUG_DHCPCTL
    109 	log_debug("dhcpctl_connect(%s:%d)", server_name, port);
    110 #endif
    111 
    112 	status = omapi_generic_new (connection, MDL);
    113 	if (status != ISC_R_SUCCESS) {
    114 		return status;
    115 	}
    116 
    117 	status = omapi_protocol_connect (*connection, server_name,
    118 					 (unsigned)port, authinfo);
    119 	if (status == ISC_R_SUCCESS) {
    120 #ifdef DEBUG_DHCPCTL
    121 		log_debug("dhcpctl_connect success");
    122 #endif
    123 		return status;
    124 	}
    125 
    126 	if (status != DHCP_R_INCOMPLETE) {
    127 		omapi_object_dereference (connection, MDL);
    128 #ifdef DEBUG_DHCPCTL
    129 		log_debug("dhcpctl_connect failed:%s",
    130 			  isc_result_totext (status));
    131 #endif
    132 		return status;
    133 	}
    134 
    135 	status = omapi_wait_for_completion (*connection, 0);
    136 	if (status != ISC_R_SUCCESS) {
    137 		omapi_object_dereference (connection, MDL);
    138 #ifdef DEBUG_DHCPCTL
    139 		log_debug("dhcpctl_connect, wait failed:%s",
    140 			  isc_result_totext (status));
    141 #endif
    142 		return status;
    143 	}
    144 
    145 #ifdef DEBUG_DHCPCTL
    146 		log_debug("dhcpctl_connect success");
    147 #endif
    148 	return status;
    149 }
    150 
    151 /* dhcpctl_timed_connect
    152 
    153    synchronous
    154    returns nonzero status code if it didn't connect, zero otherwise
    155    stores connection handle through connection, which can be used
    156    for subsequent access to the specified server.
    157    server_name is the name of the server, and port is the TCP
    158    port on which it is listening.
    159    authinfo is the handle to an object containing authentication
    160    information.
    161    How long the function waits for the connection to complete is
    162    dictated by the value of the parameter, t. If the value is nul,
    163    it will wait indefinitely. Otherwise it will wait for the amount
    164    of time specified by t (tv_sec:tv_usec). Values of zero for both
    165    fields are valid but not recommended. */
    166 dhcpctl_status dhcpctl_timed_connect (dhcpctl_handle *connection,
    167 				      const char *server_name, int port,
    168 				      dhcpctl_handle authinfo,
    169 				      struct timeval *t)
    170 {
    171 	isc_result_t status;
    172 #ifdef DEBUG_DHCPCTL
    173 	log_debug("dhcpctl_timed_connect(%s:%d)", server_name, port);
    174 #endif
    175 	status = omapi_generic_new (connection, MDL);
    176 	if (status != ISC_R_SUCCESS) {
    177 		return status;
    178 	}
    179 
    180 	status = omapi_protocol_connect (*connection, server_name,
    181 					 (unsigned)port, authinfo);
    182 
    183 	if (status == ISC_R_SUCCESS) {
    184 		return status;
    185 	}
    186 
    187 	if (status == DHCP_R_INCOMPLETE) {
    188 		isc_result_t wait_status = ISC_R_SUCCESS;
    189 
    190 		/* Wait for it to complete */
    191 		status = dhcpctl_timed_wait_for_completion(*connection,
    192 							   &wait_status, t);
    193 		if (status == ISC_R_SUCCESS) {
    194 			status = wait_status;
    195 		}
    196 	}
    197 
    198 	if (status != ISC_R_SUCCESS) {
    199 		omapi_object_dereference (connection, MDL);
    200 	}
    201 	return status;
    202 }
    203 
    204 /* dhcpctl_wait_for_completion
    205 
    206    synchronous
    207    returns zero if the callback completes, a nonzero status if
    208    there was some problem relating to the wait operation.   The
    209    status of the queued request will be stored through s, and
    210    will also be either zero for success or nonzero for some kind
    211    of failure.    Never returns until completion or until the
    212    connection to the server is lost.   This performs the same
    213    function as dhcpctl_set_callback and the subsequent callback,
    214    for programs that want to do inline execution instead of using
    215    callbacks. */
    216 
    217 dhcpctl_status dhcpctl_wait_for_completion (dhcpctl_handle h,
    218 					    dhcpctl_status *s)
    219 {
    220 #ifdef DEBUG_DHCPCTL
    221 	log_debug("dhcpctl_wait_for_completion");
    222 #endif
    223 	isc_result_t status;
    224 	status = omapi_wait_for_completion (h, 0);
    225 	if (status != ISC_R_SUCCESS) {
    226 		return status;
    227 	}
    228 	if (h -> type == dhcpctl_remote_type)
    229 		*s = ((dhcpctl_remote_object_t *)h) -> waitstatus;
    230 
    231 	return ISC_R_SUCCESS;
    232 }
    233 
    234 /* dhcpctl_timed_wait_for_completion
    235 
    236    synchronous
    237    returns zero if the callback completes, a nonzero status if
    238    there was some problem relating to the wait operation.   The
    239    status of the queued request will be stored through s, and
    240    will also be either zero for success or nonzero for some kind
    241    of failure.  How long the function waits for a response is
    242    dictated by the value of the parameter, t. If the value is nul,
    243    it will wait indefinitely or until the connection is lost.
    244    Otherwise it will wait for the amount of time specified by t
    245   (tv_sec:tv_usec). Values of zero for both fields are valid
    246    but not recommended.  The result of the request as processed on the
    247    server is returned via the parameter, s.  This performs the same
    248    function as dhcpctl_set_callback and the subsequent callback,
    249    for programs that want to do inline execution instead of using
    250    callbacks. */
    251 
    252 dhcpctl_status dhcpctl_timed_wait_for_completion (dhcpctl_handle h,
    253 						  dhcpctl_status *s,
    254 						  struct timeval *t)
    255 {
    256 	isc_result_t status;
    257 	struct timeval adjusted_t;
    258 
    259 #ifdef DEBUG_DHCPCTL
    260         if (t) {
    261 		log_debug ("dhcpctl_timed_wait_for_completion"
    262 			   "(%u.%u secs.usecs)",
    263                            (unsigned int)(t->tv_sec),
    264                            (unsigned int)(t->tv_usec));
    265         } else {
    266                 log_debug ("dhcpctl_timed_wait_for_completion(no timeout)");
    267         }
    268 #endif
    269 
    270 	if (t) {
    271 		struct timeval now;
    272 		gettimeofday (&now, (struct timezone *)0);
    273 		adjusted_t.tv_sec = now.tv_sec + t->tv_sec;
    274 		adjusted_t.tv_usec = now.tv_usec + t->tv_usec;
    275 	}
    276 
    277 	status = omapi_wait_for_completion (h, (t ? &adjusted_t : 0));
    278 	if (status != ISC_R_SUCCESS) {
    279 		return status;
    280 	}
    281 
    282 	if (h->type == dhcpctl_remote_type) {
    283 		*s = ((dhcpctl_remote_object_t *)h)->waitstatus;
    284 	}
    285 
    286 	return ISC_R_SUCCESS;
    287 }
    288 
    289 
    290 /* dhcpctl_get_value
    291 
    292    synchronous
    293    returns zero if the call succeeded, a nonzero status code if
    294    it didn't.
    295    result is the address of an empty data string (initialized
    296    with bzero or cleared with data_string_forget).   On
    297    successful completion, the addressed data string will contain
    298    the value that was fetched.
    299    dhcpctl_handle refers to some dhcpctl item
    300    value_name refers to some value related to that item - e.g.,
    301    for a handle associated with a completed host lookup, value
    302    could be one of "hardware-address", "dhcp-client-identifier",
    303    "known" or "client-hostname". */
    304 
    305 dhcpctl_status dhcpctl_get_value (dhcpctl_data_string *result,
    306 				  dhcpctl_handle h, const char *value_name)
    307 {
    308 	isc_result_t status;
    309 	omapi_value_t *tv = (omapi_value_t *)0;
    310 	unsigned len;
    311 	int ip;
    312 #ifdef DEBUG_DHCPCTL
    313 	log_debug("dhcpctl_get_value(%s)", value_name);
    314 #endif
    315 
    316 	status = omapi_get_value_str (h, (omapi_object_t *)0, value_name, &tv);
    317 	if (status != ISC_R_SUCCESS)
    318 		return status;
    319 
    320 	switch (tv -> value -> type) {
    321 	      case omapi_datatype_int:
    322 		len = sizeof (int);
    323 		break;
    324 
    325 	      case omapi_datatype_string:
    326 	      case omapi_datatype_data:
    327 		len = tv -> value -> u.buffer.len;
    328 		break;
    329 
    330 	      case omapi_datatype_object:
    331 		len = sizeof (omapi_handle_t);
    332 		break;
    333 
    334 	      default:
    335 		omapi_typed_data_dereference (&tv -> value, MDL);
    336 		return ISC_R_UNEXPECTED;
    337 	}
    338 
    339 	status = omapi_data_string_new (result, len, MDL);
    340 	if (status != ISC_R_SUCCESS) {
    341 		omapi_typed_data_dereference (&tv -> value, MDL);
    342 		return status;
    343 	}
    344 
    345 	switch (tv -> value -> type) {
    346 	      case omapi_datatype_int:
    347 		ip = htonl (tv -> value -> u.integer);
    348 		memcpy ((*result) -> value, &ip, sizeof ip);
    349 		break;
    350 
    351 	      case omapi_datatype_string:
    352 	      case omapi_datatype_data:
    353 		memcpy ((*result) -> value,
    354 			tv -> value -> u.buffer.value,
    355 			tv -> value -> u.buffer.len);
    356 		break;
    357 
    358 	      case omapi_datatype_object:
    359 		ip = htonl (tv -> value -> u.object -> handle);
    360 		memcpy ((*result) -> value, &ip, sizeof ip);
    361 		break;
    362 	}
    363 
    364 	omapi_value_dereference (&tv, MDL);
    365 	return ISC_R_SUCCESS;
    366 }
    367 
    368 /* dhcpctl_get_boolean
    369 
    370    like dhcpctl_get_value, but more convenient for boolean
    371    values, since no data_string needs to be dealt with. */
    372 
    373 dhcpctl_status dhcpctl_get_boolean (int *result,
    374 				    dhcpctl_handle h, const char *value_name)
    375 {
    376 	isc_result_t status;
    377 	dhcpctl_data_string data = (dhcpctl_data_string)0;
    378 	int rv;
    379 
    380 #ifdef DEBUG_DHCPCTL
    381 	log_debug("dhcpctl_get_boolean(%s)", value_name);
    382 #endif
    383 
    384 	status = dhcpctl_get_value (&data, h, value_name);
    385 	if (status != ISC_R_SUCCESS)
    386 		return status;
    387 	if (data -> len != sizeof rv) {
    388 		omapi_data_string_dereference (&data, MDL);
    389 		return ISC_R_UNEXPECTED;
    390 	}
    391 	memcpy (&rv, data -> value, sizeof rv);
    392 	*result = ntohl (rv);
    393 	omapi_data_string_dereference (&data, MDL);
    394 	return ISC_R_SUCCESS;
    395 }
    396 
    397 /* dhcpctl_set_value
    398 
    399    Sets a value on an object referred to by a dhcpctl_handle.
    400    The opposite of dhcpctl_get_value.   Does not update the
    401    server - just sets the value on the handle. */
    402 
    403 dhcpctl_status dhcpctl_set_value (dhcpctl_handle h, dhcpctl_data_string value,
    404 				  const char *value_name)
    405 {
    406 	isc_result_t status;
    407 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
    408 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    409 #ifdef DEBUG_DHCPCTL
    410 	log_debug("dhcpctl_set_value(%s)", value_name);
    411 #endif
    412 
    413 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
    414 	if (status != ISC_R_SUCCESS)
    415 		return status;
    416 	memcpy (name -> value, value_name, strlen (value_name));
    417 
    418 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_data,
    419 				       value -> len);
    420 	if (status != ISC_R_SUCCESS) {
    421 		omapi_data_string_dereference (&name, MDL);
    422 		return status;
    423 	}
    424 	memcpy (tv -> u.buffer.value, value -> value, value -> len);
    425 
    426 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
    427 	omapi_data_string_dereference (&name, MDL);
    428 	omapi_typed_data_dereference (&tv, MDL);
    429 	return status;
    430 }
    431 
    432 /* dhcpctl_set_string_value
    433 
    434    Sets a NUL-terminated ASCII value on an object referred to by
    435    a dhcpctl_handle.   like dhcpctl_set_value, but saves the
    436    trouble of creating a data_string for a NUL-terminated string.
    437    Does not update the server - just sets the value on the handle. */
    438 
    439 dhcpctl_status dhcpctl_set_string_value (dhcpctl_handle h, const char *value,
    440 					 const char *value_name)
    441 {
    442 	isc_result_t status;
    443 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
    444 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    445 #ifdef DEBUG_DHCPCTL
    446 	log_debug("dhcpctl_set_string_value(%s)", value_name);
    447 #endif
    448 
    449 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
    450 	if (status != ISC_R_SUCCESS)
    451 		return status;
    452 	memcpy (name -> value, value_name, strlen (value_name));
    453 
    454 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_string, value);
    455 	if (status != ISC_R_SUCCESS) {
    456 		omapi_data_string_dereference (&name, MDL);
    457 		return status;
    458 	}
    459 
    460 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
    461 	omapi_data_string_dereference (&name, MDL);
    462 	omapi_typed_data_dereference (&tv, MDL);
    463 	return status;
    464 }
    465 
    466 /* dhcpctl_set_buffer_value
    467 
    468    Sets a value on an object referred to by a dhcpctl_handle.  like
    469    dhcpctl_set_value, but saves the trouble of creating a data_string
    470    for string for which we have a buffer and length.  Does not update
    471    the server - just sets the value on the handle. */
    472 
    473 dhcpctl_status dhcpctl_set_data_value (dhcpctl_handle h,
    474 				       const char *value, unsigned len,
    475 				       const char *value_name)
    476 {
    477 	isc_result_t status;
    478 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
    479 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    480 	unsigned ll;
    481 #ifdef DEBUG_DHCPCTL
    482 	log_debug("dhcpctl_set_data_value(%s)", value_name);
    483 #endif
    484 
    485 	ll = strlen (value_name);
    486 	status = omapi_data_string_new (&name, ll, MDL);
    487 	if (status != ISC_R_SUCCESS)
    488 		return status;
    489 	memcpy (name -> value, value_name, ll);
    490 
    491 	status = omapi_typed_data_new (MDL, &tv,
    492 				       omapi_datatype_data, len, value);
    493 	if (status != ISC_R_SUCCESS) {
    494 		omapi_data_string_dereference (&name, MDL);
    495 		return status;
    496 	}
    497 	memcpy (tv -> u.buffer.value, value, len);
    498 
    499 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
    500 	omapi_data_string_dereference (&name, MDL);
    501 	omapi_typed_data_dereference (&tv, MDL);
    502 	return status;
    503 }
    504 
    505 /* dhcpctl_set_null_value
    506 
    507    Sets a null value on an object referred to by a dhcpctl_handle. */
    508 
    509 dhcpctl_status dhcpctl_set_null_value (dhcpctl_handle h,
    510 				       const char *value_name)
    511 {
    512 	isc_result_t status;
    513 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    514 	unsigned ll;
    515 #ifdef DEBUG_DHCPCTL
    516 	log_debug("dhcpctl_set_null_value(%s)", value_name);
    517 #endif
    518 
    519 	ll = strlen (value_name);
    520 	status = omapi_data_string_new (&name, ll, MDL);
    521 	if (status != ISC_R_SUCCESS)
    522 		return status;
    523 	memcpy (name -> value, value_name, ll);
    524 
    525 	status = omapi_set_value (h, (omapi_object_t *)0, name,
    526 				  (omapi_typed_data_t *)0);
    527 	omapi_data_string_dereference (&name, MDL);
    528 	return status;
    529 }
    530 
    531 /* dhcpctl_set_boolean_value
    532 
    533    Sets a boolean value on an object - like dhcpctl_set_value,
    534    only more convenient for booleans. */
    535 
    536 dhcpctl_status dhcpctl_set_boolean_value (dhcpctl_handle h, int value,
    537 					  const char *value_name)
    538 {
    539 	isc_result_t status;
    540 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
    541 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    542 #ifdef DEBUG_DHCPCTL
    543 	log_debug("dhcpctl_set_boolean_value(%s)", value_name);
    544 #endif
    545 
    546 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
    547 	if (status != ISC_R_SUCCESS)
    548 		return status;
    549 	memcpy (name -> value, value_name, strlen (value_name));
    550 
    551 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
    552 	if (status != ISC_R_SUCCESS) {
    553 		omapi_data_string_dereference (&name, MDL);
    554 		return status;
    555 	}
    556 
    557 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
    558 	omapi_data_string_dereference (&name, MDL);
    559 	omapi_typed_data_dereference (&tv, MDL);
    560 	return status;
    561 }
    562 
    563 /* dhcpctl_set_int_value
    564 
    565    Sets a boolean value on an object - like dhcpctl_set_value,
    566    only more convenient for booleans. */
    567 
    568 dhcpctl_status dhcpctl_set_int_value (dhcpctl_handle h, int value,
    569 				      const char *value_name)
    570 {
    571 	isc_result_t status;
    572 	omapi_typed_data_t *tv = (omapi_typed_data_t *)0;
    573 	omapi_data_string_t *name = (omapi_data_string_t *)0;
    574 #ifdef DEBUG_DHCPCTL
    575 	log_debug("dhcpctl_set_int_value(%s)", value_name);
    576 #endif
    577 
    578 	status = omapi_data_string_new (&name, strlen (value_name), MDL);
    579 	if (status != ISC_R_SUCCESS)
    580 		return status;
    581 	memcpy (name -> value, value_name, strlen (value_name));
    582 
    583 	status = omapi_typed_data_new (MDL, &tv, omapi_datatype_int, value);
    584 	if (status != ISC_R_SUCCESS) {
    585 		omapi_data_string_dereference (&name, MDL);
    586 		return status;
    587 	}
    588 
    589 	status = omapi_set_value (h, (omapi_object_t *)0, name, tv);
    590 	omapi_data_string_dereference (&name, MDL);
    591 	omapi_typed_data_dereference (&tv, MDL);
    592 	return status;
    593 }
    594 
    595 /* dhcpctl_object_update
    596 
    597    Queues an update on the object referenced by the handle (there
    598    can't be any other work in progress on the handle).   An
    599    update means local parameters will be sent to the server. */
    600 
    601 dhcpctl_status dhcpctl_object_update (dhcpctl_handle connection,
    602 				      dhcpctl_handle h)
    603 {
    604 	isc_result_t status;
    605 	omapi_object_t *message = (omapi_object_t *)0;
    606 	dhcpctl_remote_object_t *ro;
    607 #ifdef DEBUG_DHCPCTL
    608 	log_debug("dhcpctl_object_update");
    609 #endif
    610 
    611 	if (h -> type != dhcpctl_remote_type)
    612 		return DHCP_R_INVALIDARG;
    613 	ro = (dhcpctl_remote_object_t *)h;
    614 
    615 	status = omapi_message_new (&message, MDL);
    616 	if (status != ISC_R_SUCCESS) {
    617 		omapi_object_dereference (&message, MDL);
    618 		return status;
    619 	}
    620 	status = omapi_set_int_value (message, (omapi_object_t *)0,
    621 				      "op", OMAPI_OP_UPDATE);
    622 	if (status != ISC_R_SUCCESS) {
    623 		omapi_object_dereference (&message, MDL);
    624 		return status;
    625 	}
    626 
    627 	status = omapi_set_object_value (message, (omapi_object_t *)0,
    628 					 "object", h);
    629 	if (status != ISC_R_SUCCESS) {
    630 		omapi_object_dereference (&message, MDL);
    631 		return status;
    632 	}
    633 
    634 	status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
    635 				      (int)(ro -> remote_handle));
    636 	if (status != ISC_R_SUCCESS) {
    637 		omapi_object_dereference (&message, MDL);
    638 		return status;
    639 	}
    640 
    641 	omapi_message_register (message);
    642 	status = omapi_protocol_send_message (connection -> outer,
    643 					      (omapi_object_t *)0,
    644 					      message, (omapi_object_t *)0);
    645 	omapi_object_dereference (&message, MDL);
    646 	return status;
    647 }
    648 
    649 /* Requests a refresh on the object referenced by the handle (there
    650    can't be any other work in progress on the handle).   A
    651    refresh means local parameters are updated from the server. */
    652 
    653 dhcpctl_status dhcpctl_object_refresh (dhcpctl_handle connection,
    654 				       dhcpctl_handle h)
    655 {
    656 	isc_result_t status;
    657 	omapi_object_t *message = (omapi_object_t *)0;
    658 	dhcpctl_remote_object_t *ro;
    659 #ifdef DEBUG_DHCPCTL
    660 	log_debug("dhcpctl_object_refresh");
    661 #endif
    662 
    663 	if (h -> type != dhcpctl_remote_type)
    664 		return DHCP_R_INVALIDARG;
    665 	ro = (dhcpctl_remote_object_t *)h;
    666 
    667 	status = omapi_message_new (&message, MDL);
    668 	if (status != ISC_R_SUCCESS) {
    669 		omapi_object_dereference (&message, MDL);
    670 		return status;
    671 	}
    672 	status = omapi_set_int_value (message, (omapi_object_t *)0,
    673 				      "op", OMAPI_OP_REFRESH);
    674 	if (status != ISC_R_SUCCESS) {
    675 		omapi_object_dereference (&message, MDL);
    676 		return status;
    677 	}
    678 	status = omapi_set_int_value (message, (omapi_object_t *)0,
    679 				      "handle", (int)(ro -> remote_handle));
    680 	if (status != ISC_R_SUCCESS) {
    681 		omapi_object_dereference (&message, MDL);
    682 		return status;
    683 	}
    684 
    685 	omapi_message_register (message);
    686 	status = omapi_protocol_send_message (connection -> outer,
    687 					      (omapi_object_t *)0,
    688 					      message, (omapi_object_t *)0);
    689 
    690 	/* We don't want to send the contents of the object down the
    691 	   wire, but we do need to reference it so that we know what
    692 	   to do with the update. */
    693 	status = omapi_set_object_value (message, (omapi_object_t *)0,
    694 					 "object", h);
    695 	if (status != ISC_R_SUCCESS) {
    696 		omapi_object_dereference (&message, MDL);
    697 		return status;
    698 	}
    699 
    700 	omapi_object_dereference (&message, MDL);
    701 	return status;
    702 }
    703 
    704 /* Requests the removal of the object referenced by the handle (there
    705    can't be any other work in progress on the handle).   A
    706    removal means that all searchable references to the object on the
    707    server are deleted. */
    708 
    709 dhcpctl_status dhcpctl_object_remove (dhcpctl_handle connection,
    710 				      dhcpctl_handle h)
    711 {
    712 	isc_result_t status;
    713 	omapi_object_t *message = (omapi_object_t *)0;
    714 	dhcpctl_remote_object_t *ro;
    715 #ifdef DEBUG_DHCPCTL
    716 	log_debug("dhcpctl_object_remove");
    717 #endif
    718 
    719 	if (h -> type != dhcpctl_remote_type)
    720 		return DHCP_R_INVALIDARG;
    721 	ro = (dhcpctl_remote_object_t *)h;
    722 
    723 	status = omapi_message_new (&message, MDL);
    724 	if (status != ISC_R_SUCCESS) {
    725 		omapi_object_dereference (&message, MDL);
    726 		return status;
    727 	}
    728 	status = omapi_set_int_value (message, (omapi_object_t *)0,
    729 				      "op", OMAPI_OP_DELETE);
    730 	if (status != ISC_R_SUCCESS) {
    731 		omapi_object_dereference (&message, MDL);
    732 		return status;
    733 	}
    734 
    735 	status = omapi_set_int_value (message, (omapi_object_t *)0, "handle",
    736 				      (int)(ro -> remote_handle));
    737 	if (status != ISC_R_SUCCESS) {
    738 		omapi_object_dereference (&message, MDL);
    739 		return status;
    740 	}
    741 
    742 	status = omapi_set_object_value (message, (omapi_object_t *)0,
    743 					 "notify-object", h);
    744 	if (status != ISC_R_SUCCESS) {
    745 		omapi_object_dereference (&message, MDL);
    746 		return status;
    747 	}
    748 
    749 	omapi_message_register (message);
    750 	status = omapi_protocol_send_message (connection -> outer,
    751 					      (omapi_object_t *)0,
    752 					      message, (omapi_object_t *)0);
    753 	omapi_object_dereference (&message, MDL);
    754 	return status;
    755 }
    756 
    757 isc_result_t dhcpctl_data_string_dereference (dhcpctl_data_string *vp,
    758 					      const char *file, int line)
    759 {
    760 #ifdef DEBUG_DHCPCTL
    761 	log_debug("dhcpctl_data_string_dereference");
    762 #endif
    763 	return omapi_data_string_dereference (vp, file, line);
    764 }
    765 
    766 dhcpctl_status dhcpctl_disconnect (dhcpctl_handle *connection,
    767 				   int force)
    768 {
    769 	isc_result_t status;
    770 #ifdef DEBUG_DHCPCTL
    771 	log_debug("dhcpctl_disconnect()");
    772 #endif
    773 	if (!connection || !((*connection)->outer) ||
    774 	    !((*connection)->outer->type) ||
    775 	     ((*connection)->outer->type != omapi_type_protocol) ||
    776 	     !((*connection)->outer->outer)) {
    777 		log_debug("dhcpctl_disconnect detected invalid arg");
    778                 return DHCP_R_INVALIDARG;
    779 	}
    780 
    781 	status = omapi_disconnect ((*connection)->outer->outer, force);
    782 	if (status == ISC_R_SUCCESS) {
    783 #ifdef DEBUG_DHCPCTL
    784 		log_debug("dhcpctl_disconnect success");
    785 #endif
    786 		omapi_object_dereference (connection, MDL);
    787 		return status;
    788 	}
    789 
    790 #ifdef DEBUG_DHCPCTL
    791 	log_debug("dhcpctl_disconnect failed:%s",
    792 		   isc_result_totext (status));
    793 #endif
    794 	return status;
    795 }
    796 
    797