view usr/src/cmd/cmd-inet/usr.sadm/dhcpmgr/lib/network.c @ 4:1a15d5aaf794

synchronized with onnv_86 (6202) in onnv-gate
author Koji Uno <koji.uno@sun.com>
date Mon, 31 Aug 2009 14:38:03 +0900
parents c9caec207d52
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <string.h>
#include <dhcp_svc_private.h>
#include <dhcp_svc_confkey.h>
#include <libinetutil.h>
#include <libintl.h>
#include <stdlib.h>
#include <ctype.h>
#include <malloc.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <jni.h>
#include <com_sun_dhcpmgr_bridge_Bridge.h>

#include "exception.h"
#include "dd_misc.h"
#include "class_cache.h"

/*
 * Create a dn_rec from a DhcpClientRecord.
 */
static dn_rec_t *
create_dnrec(JNIEnv *env,
	jobject dhcpClientRecord)
{
	jclass dcr_class;

	dn_rec_t *dnrec = NULL;
	char *str;
	unsigned int cid_len;

	/* Locate the class we need */
	dcr_class = find_class(env, DCR_CLASS);
	if (dcr_class == NULL) {
		/* exception thrown */
		return (NULL);
	}

	dnrec = malloc(sizeof (dn_rec_t));
	if (dnrec == NULL) {
		throw_memory_exception(env);
		return (NULL);
	}

	/*
	 * Get the cid and the cid_len.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETCID, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	cid_len = DN_MAX_CID_LEN;
	if (hexascii_to_octet(str, strlen(str), dnrec->dn_cid, &cid_len) != 0) {
		free(str);
		free_dnrec(dnrec);
		throw_memory_exception(env);
		return (NULL);
	}
	dnrec->dn_cid_len = cid_len;
	free(str);

	/*
	 * Get the flags.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETFLAG, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	dnrec->dn_flags = atoi(str);
	free(str);

	/*
	 * Get the client IP.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETCIP, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	dnrec->dn_cip.s_addr = ntohl(inet_addr(str));
	free(str);

	/*
	 * Get the server IP.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETSIP, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	dnrec->dn_sip.s_addr = ntohl(inet_addr(str));
	free(str);

	/*
	 * Get the expiration.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETEXP, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	dnrec->dn_lease = atol(str);
	free(str);

	/*
	 * Get the signature.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETSIG, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	dnrec->dn_sig = atoll(str);
	free(str);

	/*
	 * Get the macro.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETMAC, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	(void) strlcpy(dnrec->dn_macro, str, sizeof (dnrec->dn_macro));
	free(str);

	/*
	 * Get the comment.
	 */
	if (!dd_get_str_attr(env, dcr_class, DCR_GETCMT, dhcpClientRecord,
		&str)) {
		/* exception thrown */
		free_dnrec(dnrec);
		return (NULL);
	}
	(void) strlcpy(dnrec->dn_comment, str, sizeof (dnrec->dn_comment));
	free(str);

	return (dnrec);
}

/*
 * Create a DhcpClientRecord from a dn_rec.
 */
static jobject
create_DhcpClientRecord(
	JNIEnv *env,
	dn_rec_t *dnrec)
{
	jclass dcr_class;
	jmethodID dcr_cons;
	jobject dhcpClientRecord;
	struct in_addr tmpaddr;

	char ascii_cid[DN_MAX_CID_LEN * 2 + 1];
	char ascii_flags[2 + 1];
	char ascii_cip[IPADDR_MAX_CHAR + 1];
	char ascii_sip[IPADDR_MAX_CHAR + 1];
	char ascii_lease[ULONG_MAX_CHAR + 1];
	char ascii_sig[UINT64_MAX_CHAR + 1];
	char ascii_macro[DSVC_MAX_MACSYM_LEN + 1];
	char ascii_comment[DN_MAX_COMMENT_LEN + 1];

	uint_t cid_len;
	int err;

	/* Find the class */
	dcr_class = find_class(env, DCR_CLASS);
	if (dcr_class == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Locate the constructor we need */
	dcr_cons = get_methodID(env, dcr_class, DCR_CONS);
	if (dcr_cons == NULL) {
		/* exception thrown */
		return (NULL);
	}

	cid_len = DN_MAX_CID_LEN * 2 + 1;
	err = octet_to_hexascii(dnrec->dn_cid, dnrec->dn_cid_len, ascii_cid,
	    &cid_len);
	if (err != 0) {
		throw_bridge_exception(env, strerror(err));
		return (NULL);
	}
	ascii_cid[cid_len] = '\0';

	(void) sprintf(ascii_flags, "%02hu", dnrec->dn_flags);

	tmpaddr.s_addr = htonl(dnrec->dn_cip.s_addr);
	(void) strcpy(ascii_cip, inet_ntoa(tmpaddr));
	tmpaddr.s_addr = htonl(dnrec->dn_sip.s_addr);
	(void) strcpy(ascii_sip, inet_ntoa(tmpaddr));

	(void) sprintf(ascii_lease, "%d", dnrec->dn_lease);
	(void) sprintf(ascii_sig, "%lld", dnrec->dn_sig);

	(void) strlcpy(ascii_macro, dnrec->dn_macro, sizeof (ascii_macro));
	(void) strlcpy(ascii_comment, dnrec->dn_comment,
	    sizeof (ascii_comment));

	dhcpClientRecord = (*env)->NewObject(env, dcr_class, dcr_cons,
		(*env)->NewStringUTF(env, ascii_cid),
		(*env)->NewStringUTF(env, ascii_flags),
		(*env)->NewStringUTF(env, ascii_cip),
		(*env)->NewStringUTF(env, ascii_sip),
		(*env)->NewStringUTF(env, ascii_lease),
		(*env)->NewStringUTF(env, ascii_macro),
		(*env)->NewStringUTF(env, ascii_comment),
		(*env)->NewStringUTF(env, ascii_sig));

	return (dhcpClientRecord);
}

/*
 * Given a network name, find it's IP address.
 */
static boolean_t
getNetIPByName(const char *netname, char *netip) {

	struct netent *ne;
	ulong_t addr;
	boolean_t result = B_FALSE;

	if ((ne = getnetbyname(netname)) != NULL &&
		ne->n_addrtype == AF_INET) {

		int i;
		ulong_t tl;
		int count;

		for (i = 0, tl = (ulong_t)0xff000000, count = 0;
			i < 4; i++, tl >>= 8) {

			if ((ne->n_net & tl) == 0)
				count += 8;
			else
				break;
		}

		addr = ne->n_net << count;
		(void) sprintf(netip, "%ld.%ld.%ld.%ld",
		((addr & 0xff000000) >> 24), ((addr & 0x00ff0000) >> 16),
		((addr & 0x0000ff00) >> 8), (addr & 0x000000ff));

		result = B_TRUE;
	}

	return (result);
}

/*
 * Create a Network object for a network IP address.
 */
static jobject
createNetwork(
	JNIEnv *env,
	const char *network)
{
	jclass net_class;
	jmethodID net_cons;
	jobject net;

	struct in_addr addr;
	struct in_addr mask;
	jstring jstr;

	/* Locate the class and methods we need */
	net_class = find_class(env, NET_CLASS);
	if (net_class == NULL) {
		/* exception thrown */
		return (NULL);
	}
	net_cons = get_methodID(env, net_class, NET_CONS);
	if (net_cons == NULL) {
		/* exception thrown */
		return (NULL);
	}

	addr.s_addr = ntohl(inet_addr(network));
	get_netmask4(&addr, &mask);

	jstr = (*env)->NewStringUTF(env, network);
	if (jstr == NULL) {
		/* exception thrown */
		return (NULL);
	}

	net = (*env)->NewObject(env, net_class, net_cons, jstr, mask.s_addr);

	return (net);
}


/*
 * Get the Network object for the network argument.
 */
/*ARGSUSED*/
JNIEXPORT jobject JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_getNetwork(
	JNIEnv *env,
	jobject obj,
	jstring jnet)
{

	jobject netObj;
	char *net;

	char *netip = NULL;
	char ascii_ip[IPADDR_MAX_CHAR + 1];

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		return (NULL);
	}

	/*
	 * If net looks like an IP address, assume it is,
	 * otherwise go get its IP
	 */
	if (!isdigit(*net)) {
		if (getNetIPByName(net, ascii_ip)) {
			netip = ascii_ip;
		}
	} else {
		netip = net;
	}

	/* If we could not find an IP for net, then return NULL object */
	if (netip == NULL) {
		free(net);
		return (NULL);
	}

	/* Create a Network object */
	netObj = createNetwork(env, netip);
	if (netObj == NULL) {
		/* exception thrown */
		free(net);
		return (NULL);
	}

	/* free up resources */
	free(net);

	/* return the object */
	return (netObj);
}

/*
 * List the networks currently under DHCP management.  Return as an array
 * of Network objects including the subnet mask for each network.
 */
/*ARGSUSED*/
JNIEXPORT jobjectArray JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_getNetworks(
    JNIEnv *env,
    jobject obj,
    jobject jdatastore)
{
	jclass net_class;
	jobjectArray jlist = NULL;
	jobject net;
	uint32_t count;
	char **list = NULL;
	dsvc_datastore_t datastore;
	int rcode;
	int i;

	/* Locate the class. */
	net_class = find_class(env, NET_CLASS);
	if (net_class == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return (NULL);
	}

	/* Get the list of network tables */
	rcode = list_dd(&datastore, DSVC_DHCPNETWORK, &list, &count);

	dd_free_datastore_t(&datastore);

	if (rcode != DSVC_SUCCESS) {
		throw_libdhcpsvc_exception(env, rcode);
		return (NULL);
	}

	/* Construct the array */
	jlist = (*env)->NewObjectArray(env, count, net_class, NULL);
	if (jlist == NULL) {
		/* exception thrown */
		for (i = 0; i < count; i++) {
		    free(list[i]);
		}
		free(list);
		return (NULL);
	}

	/* For each network, create an object and add it to the array */
	for (i = 0; i < count; i++) {
		net = createNetwork(env, list[i]);
		if (net == NULL) {
			/* exception thrown */
			break;
		}

		(*env)->SetObjectArrayElement(env, jlist, i, net);
		if ((*env)->ExceptionOccurred(env) != NULL) {
			break;
		}
	}

	/*
	 * Free the list now.
	 */
	for (i = 0; i < count; i++) {
	    free(list[i]);
	}
	free(list);

	return (jlist);
}

/*
 * Use the current datastore to create a network table in a new datastore.
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_cvtNetwork(
    JNIEnv *env,
    jobject obj,
    jstring jnet,
    jobject jdatastore)
{
	dn_rec_t record;
	dn_rec_list_t *recordList;
	dn_rec_list_t *originalList = NULL;
	uint32_t query;
	uint32_t count = 0;
	struct in_addr tmpaddr;
	char ascii_cip[IPADDR_MAX_CHAR + 1];

	dsvc_handle_t curHandle;
	dsvc_handle_t newHandle;
	dsvc_datastore_t curDatastore;
	dsvc_datastore_t newDatastore;

	char *net;
	int rcode;
	int i;

	/* Get the current data store configuration */
	if (!dd_get_conf_datastore_t(env, &curDatastore)) {
		/* exception thrown */
		return;
	}

	/* Make a "new" dsvc_datastore_t */
	if (!dd_make_datastore_t(env, &newDatastore, jdatastore)) {
		/* exception thrown */
		dd_free_datastore_t(&curDatastore);
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&curDatastore);
		dd_free_datastore_t(&newDatastore);
		return;
	}

	/* Open the current network table */
	rcode = open_dd(&curHandle, &curDatastore, DSVC_DHCPNETWORK, net,
		DSVC_READ);

	dd_free_datastore_t(&curDatastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		dd_free_datastore_t(&newDatastore);
		free(net);
		return;
	}

	/* Open the new network table */
	rcode = open_dd(&newHandle, &newDatastore, DSVC_DHCPNETWORK, net,
		DSVC_CREATE | DSVC_READ | DSVC_WRITE);

	dd_free_datastore_t(&newDatastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		(void) close_dd(&curHandle);
		free(net);
		return;
	}
	free(net);

	/* Get the records */
	DSVC_QINIT(query);
	rcode = lookup_dd(curHandle, B_FALSE, query, -1, &record,
			(void**)&recordList, &count);

	(void) close_dd(&curHandle);
	if (rcode != DSVC_SUCCESS) {
		throw_libdhcpsvc_exception(env, rcode);
		(void) close_dd(&newHandle);
		return;
	}

	if (count != 0) {
		originalList = recordList;
	}

	/* For each row, write client record to new table */
	for (i = 0; i < count; i++) {
		/* Now add the record */
		rcode = add_dd_entry(newHandle, recordList->dnl_rec);

		if (rcode != DSVC_SUCCESS) {
			tmpaddr.s_addr =
				htonl(recordList->dnl_rec->dn_cip.s_addr);
			(void) strcpy(ascii_cip, inet_ntoa(tmpaddr));
			throw_add_dd_entry_exception(env, rcode, ascii_cip);
			break;
		}

		recordList = recordList->dnl_next;
	}

	(void) close_dd(&newHandle);

	if (originalList != NULL) {
		free_dnrec_list(originalList);
	}
}

/*
 * Retrieve all of the records in a particular network table.  Returns an
 * array of DhcpClientRecord.
 */
/*ARGSUSED*/
JNIEXPORT jobjectArray JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_loadNetwork(
    JNIEnv *env,
    jobject obj,
    jstring jnet,
    jobject jdatastore)
{
	jclass dcr_class;
	jobjectArray jlist = NULL;
	jobject dhcpClientRecord;
	int i;

	dsvc_handle_t handle;
	dsvc_datastore_t datastore;

	dn_rec_t record;
	dn_rec_list_t *recordList = NULL;
	dn_rec_list_t *originalList = NULL;
	uint32_t query;
	uint32_t count = 0;

	char *net;
	int rcode;

	/* Locate the class and constructor we need */
	dcr_class = find_class(env, DCR_CLASS);
	if (dcr_class == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return (NULL);
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return (NULL);
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK, net, DSVC_READ);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		free(net);
		return (NULL);
	}
	free(net);

	/* Get the records */
	DSVC_QINIT(query);
	rcode = lookup_dd(handle, B_FALSE, query, -1, &record,
			(void**)&recordList, &count);

	(void) close_dd(&handle);
	if (rcode != DSVC_SUCCESS) {
		throw_libdhcpsvc_exception(env, rcode);
		return (NULL);
	}

	/* Save original pointer so we can free it correctly at end */
	originalList = recordList;

	/* Construct the array */
	jlist = (*env)->NewObjectArray(env, count, dcr_class, NULL);
	if (jlist == NULL) {
		/* exception thrown */
		if (originalList != NULL) {
			free_dnrec_list(originalList);
		}
		return (NULL);
	}

	/* For each client, create an object and add it to the array */
	for (i = 0; i < count; i++) {
		dhcpClientRecord = create_DhcpClientRecord(env,
					recordList->dnl_rec);
		if (dhcpClientRecord == NULL) {
			/* exception thrown */
			break;
		}
		recordList = recordList->dnl_next;

		(*env)->SetObjectArrayElement(env, jlist, i, dhcpClientRecord);
		if ((*env)->ExceptionOccurred(env) != NULL) {
			break;
		}
	}

	if (originalList != NULL) {
		free_dnrec_list(originalList);
	}

	return (jlist);
}

/*
 * Create a client record
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_createDhcpClientRecord(
    JNIEnv *env,
    jobject obj,
    jobject jrec,
    jstring jnet,
    jobject jdatastore)
{
	dsvc_handle_t handle;
	dsvc_datastore_t datastore;
	dn_rec_t *dnrec;
	char *net;
	int rcode;

	struct in_addr tmpaddr;
	char ascii_cip[IPADDR_MAX_CHAR + 1];

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return;
	}

	dnrec = create_dnrec(env, jrec);
	if (dnrec == NULL) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		free(net);
		return;
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK,
		net, DSVC_WRITE);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		free(net);
		free_dnrec(dnrec);
		return;
	}
	free(net);

	/* Now add the record */
	rcode = add_dd_entry(handle, dnrec);

	(void) close_dd(&handle);
	if (rcode != DSVC_SUCCESS) {
		tmpaddr.s_addr = htonl(dnrec->dn_cip.s_addr);
		(void) strcpy(ascii_cip, inet_ntoa(tmpaddr));
		throw_add_dd_entry_exception(env, rcode, ascii_cip);
	}

	free_dnrec(dnrec);

}

/*
 * Modify a client record.  Supply both old and new record and table in
 * which they're to be modified.
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_modifyDhcpClientRecord(
    JNIEnv *env,
    jobject obj,
    jobject joldrec,
    jobject jnewrec,
    jstring jnet,
    jobject jdatastore)
{
	dsvc_handle_t handle;
	dsvc_datastore_t datastore;
	dn_rec_t *dnoldrec;
	dn_rec_t *dnnewrec;

	struct in_addr tmpaddr;
	char old_ascii_cip[IPADDR_MAX_CHAR + 1];
	char new_ascii_cip[IPADDR_MAX_CHAR + 1];

	char *net;
	int rcode;

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return;
	}

	dnoldrec = create_dnrec(env, joldrec);
	if (dnoldrec == NULL) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		free(net);
		return;
	}

	dnnewrec = create_dnrec(env, jnewrec);
	if (dnnewrec == NULL) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		free(net);
		free_dnrec(dnoldrec);
		return;
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK,
		net, DSVC_WRITE);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		free(net);
		free_dnrec(dnoldrec);
		free_dnrec(dnnewrec);
		return;
	}
	free(net);

	/* Modify the record */
	rcode = modify_dd_entry(handle, dnoldrec, dnnewrec);

	(void) close_dd(&handle);
	if (rcode != DSVC_SUCCESS) {
		tmpaddr.s_addr = htonl(dnoldrec->dn_cip.s_addr);
		(void) strcpy(old_ascii_cip, inet_ntoa(tmpaddr));
		tmpaddr.s_addr = htonl(dnnewrec->dn_cip.s_addr);
		(void) strcpy(new_ascii_cip, inet_ntoa(tmpaddr));
		throw_modify_dd_entry_exception(env, rcode, old_ascii_cip,
			new_ascii_cip);
	}

	free_dnrec(dnnewrec);
	free_dnrec(dnoldrec);
}

/*
 * Delete a client record
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_deleteDhcpClientRecord(
    JNIEnv *env,
    jobject obj,
    jobject jrec,
    jstring jnet,
    jobject jdatastore)
{
	dsvc_handle_t handle;
	dsvc_datastore_t datastore;
	dn_rec_t *dnrec;

	struct in_addr tmpaddr;
	char ascii_cip[IPADDR_MAX_CHAR + 1];

	char *net;
	int rcode;

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return;
	}

	dnrec = create_dnrec(env, jrec);
	if (dnrec == NULL) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		free(net);
		return;
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK,
		net, DSVC_WRITE);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		free(net);
		free_dnrec(dnrec);
		return;
	}
	free(net);

	/* Delete the record */
	rcode = delete_dd_entry(handle, dnrec);

	(void) close_dd(&handle);
	if (rcode != DSVC_SUCCESS) {
		tmpaddr.s_addr = htonl(dnrec->dn_cip.s_addr);
		(void) strcpy(ascii_cip, inet_ntoa(tmpaddr));
		throw_delete_dd_entry_exception(env, rcode, ascii_cip);
	}

	free_dnrec(dnrec);
}

/*
 * Retrieve a client record
 */
/*ARGSUSED*/
JNIEXPORT jobject JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_getDhcpClientRecord(
    JNIEnv *env,
    jobject obj,
    jobject jrec,
    jstring jnet,
    jobject jdatastore)
{
	jclass dcr_class;
	jmethodID dcr_getcip;
	jobject dhcpClientRecord = NULL;
	jstring jaddr;

	dsvc_handle_t handle;
	dsvc_datastore_t datastore;

	char *net;
	char *addr;
	int rcode;

	dn_rec_t record;
	dn_rec_list_t *recordList;
	uint32_t query;
	uint32_t count = 0;

	/* Find the class and method we need */
	dcr_class = find_class(env, DCR_CLASS);
	if (dcr_class == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Locate the method id we need */
	dcr_getcip = get_methodID(env, dcr_class, DCR_GETCIP);
	if (dcr_getcip == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Get the address from the record */
	jaddr = (*env)->CallObjectMethod(env, jrec, dcr_getcip);
	if (jaddr == NULL) {
		/* exception thrown */
		return (NULL);
	}

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return (NULL);
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return (NULL);
	}

	/* Convert the address to a native string */
	if (!dd_jstring_to_UTF(env, jaddr, &addr)) {
		/* exception thrown */
		throw_memory_exception(env);
		dd_free_datastore_t(&datastore);
		free(net);
		return (NULL);
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK, net, DSVC_READ);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_open_dd_exception(env, rcode, net);
		free(addr);
		free(net);
		return (NULL);
	}
	free(net);

	/* Get the record */
	DSVC_QINIT(query);
	DSVC_QEQ(query, DN_QCIP);
	record.dn_cip.s_addr = ntohl(inet_addr(addr));

	rcode = lookup_dd(handle, B_FALSE, query, 1, &record,
			(void **)&recordList, &count);

	(void) close_dd(&handle);
	if (rcode == DSVC_SUCCESS) {
		if (count == 1) {
			dhcpClientRecord = create_DhcpClientRecord(env,
						recordList->dnl_rec);
			free_dnrec_list(recordList);
		} else {
			throw_noent_exception(env, addr);
		}
	} else {
		throw_libdhcpsvc_exception(env, rcode);
	}

	free(addr);


	return (dhcpClientRecord);
}

/*
 * Create a network table.
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_createDhcpNetwork(
    JNIEnv *env,
    jobject obj,
    jstring jnet,
    jobject jdatastore)
{
	dsvc_handle_t handle;
	dsvc_datastore_t datastore;
	char *net;
	int rcode;

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return;
	}

	rcode = open_dd(&handle, &datastore, DSVC_DHCPNETWORK, net,
		DSVC_CREATE | DSVC_READ | DSVC_WRITE);

	dd_free_datastore_t(&datastore);

	/*
	 * If open was successful, then close. Otherwise, if unsuccessful
	 * opening table, then map error to exception.
	 */
	if (rcode == DSVC_SUCCESS) {
		(void) close_dd(&handle);
	} else {
		throw_open_dd_exception(env, rcode, net);
	}

	free(net);
}

/*
 * Delete a network table.
 */
/*ARGSUSED*/
JNIEXPORT void JNICALL
Java_com_sun_dhcpmgr_bridge_Bridge_deleteDhcpNetwork(
    JNIEnv *env,
    jobject obj,
    jstring jnet,
    jobject jdatastore)
{
	dsvc_datastore_t datastore;
	char *net;
	int rcode;

	/* Create a dsvc_datastore_t using args and DHCP config settings */
	if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
		/* exception thrown */
		return;
	}

	/* Retrieve the net argument */
	if (!dd_jstring_to_UTF(env, jnet, &net)) {
		/* exception thrown */
		dd_free_datastore_t(&datastore);
		return;
	}

	rcode = remove_dd(&datastore, DSVC_DHCPNETWORK, net);

	dd_free_datastore_t(&datastore);
	if (rcode != DSVC_SUCCESS) {
		throw_remove_dd_exception(env, rcode, net);
	}

	free(net);
}