1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 1999-2002 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <libintl.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <malloc.h>
  33 #include <jni.h>
  34 #include <dhcp_svc_private.h>
  35 #include <dhcp_svc_confkey.h>
  36 #include <dhcp_symbol.h>
  37 #include <com_sun_dhcpmgr_bridge_Bridge.h>
  38 
  39 #include "exception.h"
  40 #include "dd_misc.h"
  41 #include "class_cache.h"
  42 
  43 /*
  44  * Validate that a symbol definition in dhcptab(4) format is valid.
  45  */
  46 static boolean_t
  47 validate_OptionValue(JNIEnv *env,
  48     const char *key,
  49     const char *value) {
  50 
  51         dhcp_symbol_t sym;
  52         char **fields;
  53         int last = 0;
  54         dsym_errcode_t dsymret;
  55 
  56         dsymret = dsym_init_parser(key, value, &fields, &sym);
  57         if (dsymret != DSYM_SUCCESS) {
  58                 throw_dsym_parser_init_exception(env, key, dsymret);
  59                 return (B_FALSE);
  60         }
  61 
  62         dsymret = dsym_parser(fields, &sym, &last, B_FALSE);
  63         if (dsymret != DSYM_SUCCESS) {
  64                 throw_dsym_parser_exception(env, key, fields, last,
  65                         dsymret);
  66         }
  67 
  68         dsym_close_parser(fields, &sym);
  69         return (dsymret == DSYM_SUCCESS);
  70 }
  71 
  72 /*
  73  * Create a dt_rec from a DhcptabRecord.
  74  */
  75 static dt_rec_t *
  76 create_dtrec(
  77     JNIEnv *env,
  78     jobject dhcptabRecord,
  79     boolean_t validate)
  80 {
  81         jclass dtr_class;
  82         dt_rec_t *dtrec;
  83         char *str;
  84 
  85         /* Locate the class we need */
  86         dtr_class = find_class(env, DTR_CLASS);
  87         if (dtr_class == NULL) {
  88                 /* exception thrown */
  89                 return (NULL);
  90         }
  91 
  92         dtrec = malloc(sizeof (dt_rec_t));
  93         if (dtrec == NULL) {
  94                 throw_memory_exception(env);
  95                 return (NULL);
  96         }
  97 
  98         if (!dd_get_str_attr(env, dtr_class, DTR_GETKEY, dhcptabRecord,
  99                 &str)) {
 100                 /* exception thrown */
 101                 free_dtrec(dtrec);
 102                 return (NULL);
 103         }
 104         (void) strlcpy(dtrec->dt_key, str, sizeof (dtrec->dt_key));
 105         free(str);
 106 
 107         if (!dd_get_str_attr(env, dtr_class, DTR_GETFLAG, dhcptabRecord,
 108                 &str)) {
 109                 /* exception thrown */
 110                 free_dtrec(dtrec);
 111                 return (NULL);
 112         }
 113         dtrec->dt_type = str[0];
 114         free(str);
 115 
 116         if (!dd_get_str_attr(env, dtr_class, DTR_GETSIG, dhcptabRecord,
 117                 &str)) {
 118                 /* exception thrown */
 119                 free_dtrec(dtrec);
 120                 return (NULL);
 121         }
 122         dtrec->dt_sig = atoll(str);
 123         free(str);
 124 
 125         if (!dd_get_str_attr(env, dtr_class, DTR_GETVAL, dhcptabRecord,
 126                 &dtrec->dt_value)) {
 127                 /* exception thrown */
 128                 free_dtrec(dtrec);
 129                 return (NULL);
 130         }
 131 
 132         if (validate) {
 133                 if (dtrec->dt_type == DT_SYMBOL) {
 134                         if (!validate_OptionValue(env, dtrec->dt_key,
 135                             dtrec->dt_value)) {
 136                                 /* exception thrown */
 137                                 free_dtrec(dtrec);
 138                                 return (NULL);
 139                         }
 140                 }
 141         }
 142         return (dtrec);
 143 }
 144 
 145 /*
 146  * Create a Macro from a dt_rec.
 147  */
 148 static jobject
 149 create_Macro(
 150     JNIEnv *env,
 151     const dt_rec_t *dtrec)
 152 {
 153         jobject dhcptabRecord;
 154         jclass class;
 155         jmethodID cons;
 156 
 157         char ascii_sig[UINT64_MAX_CHAR + 1];
 158 
 159         /* Find the class we need */
 160         class = find_class(env, MAC_CLASS);
 161         if (class == NULL) {
 162                 /* exception thrown */
 163                 return (NULL);
 164         }
 165 
 166         /* Locate the class constructor we need */
 167         cons = get_methodID(env, class, MAC_CONS);
 168         if (cons == NULL) {
 169                 /* exception thrown */
 170                 return (NULL);
 171         }
 172 
 173         (void) sprintf(ascii_sig, "%lld", dtrec->dt_sig);
 174         dhcptabRecord = (*env)->NewObject(env, class, cons,
 175                 (*env)->NewStringUTF(env, dtrec->dt_key),
 176                 (*env)->NewStringUTF(env, dtrec->dt_value),
 177                 (*env)->NewStringUTF(env, ascii_sig));
 178 
 179         if ((*env)->ExceptionOccurred(env) != NULL) {
 180                 dhcptabRecord = NULL;
 181         }
 182 
 183         return (dhcptabRecord);
 184 }
 185 
 186 /*
 187  * Create an Array of vendor classes.
 188  */
 189 static jobjectArray
 190 create_vendors(JNIEnv *env,
 191     dhcp_classes_t *classes) {
 192 
 193         jclass class;
 194         jobjectArray jlist = NULL;
 195         int i;
 196 
 197         class = (*env)->FindClass(env, "java/lang/String");
 198         if (class == NULL) {
 199                 /* exception thrown */
 200                 return (NULL);
 201         }
 202 
 203         /* Construct the array */
 204         jlist = (*env)->NewObjectArray(env, classes->dc_cnt, class, NULL);
 205         if (jlist == NULL) {
 206                 /* exception thrown */
 207                 return (NULL);
 208         }
 209 
 210         /* For each vendor, create an object and add it to the array */
 211         for (i = 0; i < classes->dc_cnt; i++) {
 212                 (*env)->SetObjectArrayElement(env, jlist, i,
 213                             (*env)->NewStringUTF(env, classes->dc_names[i]));
 214                 if ((*env)->ExceptionOccurred(env) != NULL) {
 215                         jlist = NULL;
 216                         break;
 217                 }
 218         }
 219         return (jlist);
 220 }
 221 
 222 /*
 223  * Create an Option from a dt_rec.
 224  */
 225 static jobject
 226 create_Option(
 227     JNIEnv *env,
 228     const char *key,
 229     const char *value,
 230     uint64_t sig,
 231     boolean_t force)
 232 {
 233         jobject dhcptabRecord = NULL;
 234         jclass class;
 235         jmethodID cons;
 236 
 237         char ascii_sig[UINT64_MAX_CHAR + 1];
 238 
 239         dhcp_symbol_t sym;
 240         char **fields;
 241         int last = 0;
 242         dsym_errcode_t ret = DSYM_SUCCESS;
 243 
 244         /* Find the class we need */
 245         class = find_class(env, OPT_CLASS);
 246         if (class == NULL) {
 247                 /* exception thrown */
 248                 return (NULL);
 249         }
 250 
 251         /* Locate the class constructor we need */
 252         cons = get_methodID(env, class, OPT_CONS);
 253         if (cons == NULL) {
 254                 /* exception thrown */
 255                 return (NULL);
 256         }
 257 
 258         (void) sprintf(ascii_sig, "%lld", sig);
 259 
 260         ret = dsym_init_parser(key, value, &fields, &sym);
 261         if (ret != DSYM_SUCCESS) {
 262                 /* throw exception */
 263                 throw_dsym_parser_init_exception(env, key, ret);
 264                 return (NULL);
 265         }
 266 
 267         ret = dsym_parser(fields, &sym, &last, force);
 268         if (ret == DSYM_SUCCESS || force) {
 269                 jboolean isValid = (ret == DSYM_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 270                 dhcptabRecord = (*env)->NewObject(env, class, cons,
 271                     (*env)->NewStringUTF(env, sym.ds_name),
 272                     (jbyte)sym.ds_category,
 273                     create_vendors(env, &sym.ds_classes),
 274                     (jshort)sym.ds_code,
 275                     (jbyte)sym.ds_type,
 276                     (jint)sym.ds_gran,
 277                     (jint)sym.ds_max,
 278                     (*env)->NewStringUTF(env, ascii_sig), isValid);
 279 
 280                 if ((*env)->ExceptionOccurred(env) != NULL) {
 281                         dhcptabRecord = NULL;
 282                 }
 283         } else {
 284                 /* throw exception */
 285                 throw_dsym_parser_exception(env, key, fields, last, ret);
 286         }
 287 
 288         dsym_close_parser(fields, &sym);
 289         return (dhcptabRecord);
 290 }
 291 
 292 /*
 293  * Retrieve an option from the dhcptab.  Returns
 294  * the record as a new instance of a Option
 295  */
 296 /*ARGSUSED*/
 297 JNIEXPORT jobject JNICALL
 298 Java_com_sun_dhcpmgr_bridge_Bridge_getOption(
 299     JNIEnv *env,
 300     jobject obj,
 301     jstring jkey,
 302     jobject jdatastore)
 303 {
 304         dsvc_datastore_t datastore;
 305         dsvc_handle_t handle;
 306 
 307         dt_rec_t record;
 308         dt_rec_list_t *recordList;
 309         uint32_t query;
 310         uint32_t count = 0;
 311 
 312         char *key;
 313         int rcode;
 314 
 315         jobject dhcptabRecord;
 316 
 317         /* Create a dsvc_datastore_t using args and DHCP config settings */
 318         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 319                 /* exception thrown */
 320                 return (NULL);
 321         }
 322 
 323         /* Retrieve the key argument */
 324         if (!dd_jstring_to_UTF(env, jkey, &key)) {
 325                 /* exception thrown */
 326                 dd_free_datastore_t(&datastore);
 327                 return (NULL);
 328         }
 329 
 330         /* Open the dhcptab */
 331         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 332                 DT_DHCPTAB, DSVC_READ);
 333 
 334         dd_free_datastore_t(&datastore);
 335         if (rcode != DSVC_SUCCESS) {
 336                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 337                 free(key);
 338                 return (NULL);
 339         }
 340 
 341         /* Get the records */
 342         DSVC_QINIT(query);
 343         DSVC_QEQ(query, DT_QTYPE | DT_QKEY);
 344         (void) strlcpy(record.dt_key, key, sizeof (record.dt_key));
 345         record.dt_type = DT_SYMBOL;
 346 
 347         rcode = lookup_dd(handle, B_FALSE, query, 1, &record,
 348                         (void**)&recordList, &count);
 349 
 350         (void) close_dd(&handle);
 351         if (rcode == DSVC_SUCCESS) {
 352                 if (count == 1) {
 353                         dhcptabRecord = create_Option(env,
 354                             recordList->dtl_rec->dt_key,
 355                             recordList->dtl_rec->dt_value,
 356                             recordList->dtl_rec->dt_sig, B_TRUE);
 357                         free_dtrec_list(recordList);
 358                 } else {
 359                         throw_noent_exception(env, key);
 360                 }
 361         } else {
 362                 throw_libdhcpsvc_exception(env, rcode);
 363         }
 364 
 365         free(key);
 366 
 367         return (dhcptabRecord);
 368 }
 369 
 370 /*
 371  * Use the current datastore to create a dhcptab table in a new datastore.
 372  */
 373 /*ARGSUSED*/
 374 JNIEXPORT void JNICALL
 375 Java_com_sun_dhcpmgr_bridge_Bridge_cvtDhcptab(
 376     JNIEnv *env,
 377     jobject obj,
 378     jobject jdatastore)
 379 {
 380 
 381         dt_rec_t record;
 382         dt_rec_list_t *recordList;
 383         dt_rec_list_t *originalList = NULL;
 384         uint32_t query;
 385         uint32_t count = 0;
 386 
 387         dsvc_handle_t curHandle;
 388         dsvc_handle_t newHandle;
 389         dsvc_datastore_t curDatastore;
 390         dsvc_datastore_t newDatastore;
 391 
 392         int rcode;
 393         int i;
 394 
 395         /* Get the current data store configuration */
 396         if (!dd_get_conf_datastore_t(env, &curDatastore)) {
 397                 /* exception thrown */
 398                 return;
 399         }
 400 
 401         /* Make a "new" dsvc_datastore_t */
 402         if (!dd_make_datastore_t(env, &newDatastore, jdatastore)) {
 403                 /* exception thrown */
 404                 dd_free_datastore_t(&curDatastore);
 405                 return;
 406         }
 407 
 408         /* Open the current dhcptab */
 409         rcode = open_dd(&curHandle, &curDatastore, DSVC_DHCPTAB,
 410                 DT_DHCPTAB, DSVC_READ);
 411 
 412         dd_free_datastore_t(&curDatastore);
 413         if (rcode != DSVC_SUCCESS) {
 414                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 415                 dd_free_datastore_t(&newDatastore);
 416                 return;
 417         }
 418 
 419         /* Open the new dhcptab */
 420         rcode = open_dd(&newHandle, &newDatastore, DSVC_DHCPTAB, DT_DHCPTAB,
 421                 DSVC_CREATE | DSVC_READ | DSVC_WRITE);
 422 
 423         dd_free_datastore_t(&newDatastore);
 424         if (rcode != DSVC_SUCCESS) {
 425                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 426                 (void) close_dd(&curHandle);
 427                 return;
 428         }
 429 
 430         /* Get the records */
 431         DSVC_QINIT(query);
 432         rcode = lookup_dd(curHandle, B_FALSE, query, -1, &record,
 433                         (void**)&recordList, &count);
 434 
 435         (void) close_dd(&curHandle);
 436         if (rcode != DSVC_SUCCESS) {
 437                 throw_libdhcpsvc_exception(env, rcode);
 438                 (void) close_dd(&newHandle);
 439                 return;
 440         }
 441 
 442         if (count != 0) {
 443                 originalList = recordList;
 444         }
 445 
 446         /* For each row, write client record to new table */
 447         for (i = 0; i < count; i++) {
 448                 /* Now add the record */
 449                 rcode = add_dd_entry(newHandle, recordList->dtl_rec);
 450 
 451                 if (rcode != DSVC_SUCCESS) {
 452                         throw_add_dd_entry_exception(env, rcode,
 453                                 recordList->dtl_rec->dt_key);
 454                         break;
 455                 }
 456 
 457                 recordList = recordList->dtl_next;
 458         }
 459 
 460         (void) close_dd(&newHandle);
 461 
 462         if (originalList != NULL) {
 463                 free_dtrec_list(originalList);
 464         }
 465 
 466 }
 467 
 468 /*
 469  * Return all options (aka symbols) currently defined in the dhcptab.
 470  * The options are returned as an array of Options.
 471  */
 472 /*ARGSUSED*/
 473 JNIEXPORT jobjectArray JNICALL
 474 Java_com_sun_dhcpmgr_bridge_Bridge_getOptions(
 475     JNIEnv *env,
 476     jobject obj,
 477     jobject jdatastore)
 478 {
 479         dsvc_datastore_t datastore;
 480         dsvc_handle_t handle;
 481 
 482         dt_rec_t record;
 483         dt_rec_list_t *recordList;
 484         dt_rec_list_t *originalList = NULL;
 485         uint32_t query;
 486         uint32_t count = 0;
 487         int rcode;
 488 
 489         jclass opt_class;
 490         jobjectArray jlist = NULL;
 491         jobject dhcptabRecord;
 492         int i;
 493 
 494         /* Find the Option class and its constructor */
 495         opt_class = find_class(env, OPT_CLASS);
 496         if (opt_class == NULL) {
 497                 /* exception thrown */
 498                 return (NULL);
 499         }
 500 
 501         /* Create a dsvc_datastore_t using args and DHCP config settings */
 502         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 503                 /* exception thrown */
 504                 return (NULL);
 505         }
 506 
 507         /* Open the dhcptab */
 508         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 509                 DT_DHCPTAB, DSVC_READ);
 510 
 511         dd_free_datastore_t(&datastore);
 512         if (rcode != DSVC_SUCCESS) {
 513                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 514                 return (NULL);
 515         }
 516 
 517         /* Get the records */
 518         DSVC_QINIT(query);
 519         DSVC_QEQ(query, DT_QTYPE);
 520         record.dt_type = DT_SYMBOL;
 521 
 522         rcode = lookup_dd(handle, B_FALSE, query, -1, &record,
 523                         (void**)&recordList, &count);
 524 
 525         (void) close_dd(&handle);
 526         if (rcode != DSVC_SUCCESS) {
 527                 throw_libdhcpsvc_exception(env, rcode);
 528                 return (NULL);
 529         }
 530 
 531         if (count != 0) {
 532                 originalList = recordList;
 533         }
 534 
 535         /* Construct the array */
 536         jlist = (*env)->NewObjectArray(env, count, opt_class, NULL);
 537         if (jlist == NULL) {
 538                 /* exception thrown */
 539                 if (originalList != NULL) {
 540                         free_dtrec_list(originalList);
 541                 }
 542                 return (NULL);
 543         }
 544 
 545         /* For each option, create an object and add it to the array */
 546         for (i = 0; i < count; i++) {
 547                 dhcptabRecord = create_Option(env,
 548                     recordList->dtl_rec->dt_key,
 549                     recordList->dtl_rec->dt_value,
 550                     recordList->dtl_rec->dt_sig, B_TRUE);
 551                 if (dhcptabRecord == NULL) {
 552                         /* exception thrown */
 553                         break;
 554                 }
 555 
 556                 (*env)->SetObjectArrayElement(env, jlist, i, dhcptabRecord);
 557                 if ((*env)->ExceptionOccurred(env) != NULL) {
 558                         break;
 559                 }
 560 
 561                 recordList = recordList->dtl_next;
 562         }
 563 
 564         if (originalList != NULL) {
 565                 free_dtrec_list(originalList);
 566         }
 567 
 568         return (jlist);
 569 }
 570 
 571 /*
 572  * Retrieve a macro from the dhcptab.  Returns
 573  * the record as a new instance of a Macro
 574  */
 575 /*ARGSUSED*/
 576 JNIEXPORT jobject JNICALL
 577 Java_com_sun_dhcpmgr_bridge_Bridge_getMacro(
 578     JNIEnv *env,
 579     jobject obj,
 580     jstring jkey,
 581     jobject jdatastore)
 582 {
 583         dsvc_datastore_t datastore;
 584         dsvc_handle_t handle;
 585 
 586         dt_rec_t record;
 587         dt_rec_list_t *recordList;
 588         uint32_t query;
 589         uint32_t count = 0;
 590 
 591         char *key;
 592         int rcode;
 593 
 594         jobject dhcptabRecord;
 595 
 596         /* Create a dsvc_datastore_t using args and DHCP config settings */
 597         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 598                 /* exception thrown */
 599                 return (NULL);
 600         }
 601 
 602         /* Retrieve the key argument */
 603         if (!dd_jstring_to_UTF(env, jkey, &key)) {
 604                 /* exception thrown */
 605                 dd_free_datastore_t(&datastore);
 606                 return (NULL);
 607         }
 608 
 609         /* Open the dhcptab */
 610         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 611                 DT_DHCPTAB, DSVC_READ);
 612 
 613         dd_free_datastore_t(&datastore);
 614         if (rcode != DSVC_SUCCESS) {
 615                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 616                 free(key);
 617                 return (NULL);
 618         }
 619 
 620         /* Get the records */
 621         DSVC_QINIT(query);
 622         DSVC_QEQ(query, DT_QTYPE | DT_QKEY);
 623         (void) strlcpy(record.dt_key, key, sizeof (record.dt_key));
 624         record.dt_type = DT_MACRO;
 625 
 626         rcode = lookup_dd(handle, B_FALSE, query, 1, &record,
 627                         (void**)&recordList, &count);
 628 
 629         (void) close_dd(&handle);
 630         if (rcode == DSVC_SUCCESS) {
 631                 if (count == 1) {
 632                         dhcptabRecord = create_Macro(env, recordList->dtl_rec);
 633                         free_dtrec_list(recordList);
 634                 } else {
 635                         throw_noent_exception(env, key);
 636                 }
 637         } else {
 638                 throw_libdhcpsvc_exception(env, rcode);
 639         }
 640 
 641         free(key);
 642 
 643         return (dhcptabRecord);
 644 }
 645 
 646 /*
 647  * Return all macros defined in the dhcptab.  Returned as an array of
 648  * Macro objects.
 649  */
 650 /*ARGSUSED*/
 651 JNIEXPORT jobjectArray JNICALL
 652 Java_com_sun_dhcpmgr_bridge_Bridge_getMacros(
 653     JNIEnv *env,
 654     jobject obj,
 655     jobject jdatastore)
 656 {
 657         dsvc_datastore_t datastore;
 658         dsvc_handle_t handle;
 659 
 660         dt_rec_t record;
 661         dt_rec_list_t *recordList;
 662         dt_rec_list_t *originalList = NULL;
 663         uint32_t query;
 664         uint32_t count = 0;
 665         int rcode;
 666 
 667         jclass mac_class;
 668         jobjectArray jlist = NULL;
 669         jobject dhcptabRecord;
 670         int i;
 671 
 672         /* Locate the Macro class and its constructor */
 673         mac_class = find_class(env, MAC_CLASS);
 674         if (mac_class == NULL) {
 675                 /* exception thrown */
 676                 return (NULL);
 677         }
 678 
 679         /* Create a dsvc_datastore_t using args and DHCP config settings */
 680         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 681                 /* exception thrown */
 682                 return (NULL);
 683         }
 684 
 685         /* Open the dhcptab */
 686         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 687                 DT_DHCPTAB, DSVC_READ);
 688 
 689         dd_free_datastore_t(&datastore);
 690         if (rcode != DSVC_SUCCESS) {
 691                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 692                 return (NULL);
 693         }
 694 
 695         /* Get the records */
 696         DSVC_QINIT(query);
 697         DSVC_QEQ(query, DT_QTYPE);
 698         record.dt_type = DT_MACRO;
 699 
 700         rcode = lookup_dd(handle, B_FALSE, query, -1, &record,
 701                         (void**)&recordList, &count);
 702 
 703         (void) close_dd(&handle);
 704         if (rcode != DSVC_SUCCESS) {
 705                 throw_libdhcpsvc_exception(env, rcode);
 706                 return (NULL);
 707         }
 708 
 709         if (count != 0) {
 710                 originalList = recordList;
 711         }
 712 
 713         /* Construct the array */
 714         jlist = (*env)->NewObjectArray(env, count, mac_class, NULL);
 715         if (jlist == NULL) {
 716                 /* exception thrown */
 717                 if (originalList != NULL) {
 718                         free_dtrec_list(originalList);
 719                 }
 720                 return (NULL);
 721         }
 722 
 723         /* For each macro, create an object and add it to the array */
 724         for (i = 0; i < count; i++) {
 725                 dhcptabRecord = create_Macro(env, recordList->dtl_rec);
 726                 if (dhcptabRecord == NULL) {
 727                         /* exception thrown */
 728                         break;
 729                 }
 730 
 731                 (*env)->SetObjectArrayElement(env, jlist, i, dhcptabRecord);
 732                 if ((*env)->ExceptionOccurred(env) != NULL) {
 733                         break;
 734                 }
 735 
 736                 recordList = recordList->dtl_next;
 737         }
 738 
 739         if (originalList != NULL) {
 740                 free_dtrec_list(originalList);
 741         }
 742 
 743         return (jlist);
 744 }
 745 
 746 /*
 747  * Function to create an Option object
 748  */
 749 /*ARGSUSED*/
 750 JNIEXPORT jobject JNICALL
 751 Java_com_sun_dhcpmgr_bridge_Bridge_createOption(
 752     JNIEnv *env,
 753     jobject obj,
 754     jstring jkey,
 755     jstring jvalue)
 756 {
 757 
 758         jobject option;
 759         char *key;
 760         char *value;
 761 
 762         /* Retrieve the key argument */
 763         if (!dd_jstring_to_UTF(env, jkey, &key)) {
 764                 /* exception thrown */
 765                 return (NULL);
 766         }
 767 
 768         /* Retrieve the value argument */
 769         if (!dd_jstring_to_UTF(env, jvalue, &value)) {
 770                 /* exception thrown */
 771                 free(key);
 772                 return (NULL);
 773         }
 774 
 775         option = create_Option(env, key, value, 0, B_FALSE);
 776 
 777         free(key);
 778         free(value);
 779 
 780         return (option);
 781 }
 782 
 783 /*
 784  * Function to create a new dhcptab record.
 785  */
 786 /*ARGSUSED*/
 787 JNIEXPORT void JNICALL
 788 Java_com_sun_dhcpmgr_bridge_Bridge_createDhcptabRecord(
 789     JNIEnv *env,
 790     jobject obj,
 791     jobject jrec,
 792     jobject jdatastore)
 793 {
 794         dsvc_handle_t handle;
 795         dsvc_datastore_t datastore;
 796         dt_rec_t *dtrec;
 797         int rcode;
 798 
 799         /* Create a dsvc_datastore_t using args and DHCP config settings */
 800         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 801                 /* exception thrown */
 802                 return;
 803         }
 804 
 805         dtrec = create_dtrec(env, jrec, B_TRUE);
 806         if (dtrec == NULL) {
 807                 /* exception thrown */
 808                 dd_free_datastore_t(&datastore);
 809                 return;
 810         }
 811 
 812         /* Open the dhcptab */
 813         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 814                 DT_DHCPTAB, DSVC_WRITE);
 815 
 816         dd_free_datastore_t(&datastore);
 817         if (rcode != DSVC_SUCCESS) {
 818                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 819                 free_dtrec(dtrec);
 820                 return;
 821         }
 822 
 823         /* Now add the record */
 824         rcode = add_dd_entry(handle, dtrec);
 825 
 826         (void) close_dd(&handle);
 827         if (rcode != DSVC_SUCCESS) {
 828                 throw_add_dd_entry_exception(env, rcode, dtrec->dt_key);
 829         }
 830 
 831         free_dtrec(dtrec);
 832 
 833 }
 834 
 835 /*
 836  * Modify a dhcptab record.
 837  */
 838 /*ARGSUSED*/
 839 JNIEXPORT void JNICALL
 840 Java_com_sun_dhcpmgr_bridge_Bridge_modifyDhcptabRecord(
 841     JNIEnv *env,
 842     jobject obj,
 843     jobject joldrec,
 844     jobject jnewrec,
 845     jobject jdatastore)
 846 {
 847         dsvc_handle_t handle;
 848         dsvc_datastore_t datastore;
 849         dt_rec_t *dtoldrec;
 850         dt_rec_t *dtnewrec;
 851         int rcode;
 852 
 853         /* Create a dsvc_datastore_t using args and DHCP config settings */
 854         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 855                 /* exception thrown */
 856                 return;
 857         }
 858 
 859         dtoldrec = create_dtrec(env, joldrec, B_FALSE);
 860         if (dtoldrec == NULL) {
 861                 /* exception thrown */
 862                 dd_free_datastore_t(&datastore);
 863                 return;
 864         }
 865 
 866         dtnewrec = create_dtrec(env, jnewrec, B_TRUE);
 867         if (dtnewrec == NULL) {
 868                 /* exception thrown */
 869                 dd_free_datastore_t(&datastore);
 870                 free_dtrec(dtoldrec);
 871                 return;
 872         }
 873 
 874         /* Open the dhcptab */
 875         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 876                 DT_DHCPTAB, DSVC_WRITE);
 877 
 878         dd_free_datastore_t(&datastore);
 879         if (rcode != DSVC_SUCCESS) {
 880                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 881                 free_dtrec(dtoldrec);
 882                 free_dtrec(dtnewrec);
 883                 return;
 884         }
 885 
 886         /* Modify the record */
 887         rcode = modify_dd_entry(handle, dtoldrec, dtnewrec);
 888 
 889         (void) close_dd(&handle);
 890         if (rcode != DSVC_SUCCESS) {
 891                 throw_modify_dd_entry_exception(env, rcode, dtoldrec->dt_key,
 892                         dtnewrec->dt_key);
 893         }
 894 
 895         free_dtrec(dtnewrec);
 896         free_dtrec(dtoldrec);
 897 
 898 }
 899 
 900 /*
 901  * Delete a record from the dhcptab
 902  */
 903 /*ARGSUSED*/
 904 JNIEXPORT void JNICALL
 905 Java_com_sun_dhcpmgr_bridge_Bridge_deleteDhcptabRecord(
 906     JNIEnv *env,
 907     jobject obj,
 908     jobject jrec,
 909     jobject jdatastore)
 910 {
 911         dsvc_handle_t handle;
 912         dsvc_datastore_t datastore;
 913         dt_rec_t *dtrec;
 914         int rcode;
 915 
 916         /* Create a dsvc_datastore_t using args and DHCP config settings */
 917         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 918                 /* exception thrown */
 919                 return;
 920         }
 921 
 922         dtrec = create_dtrec(env, jrec, B_FALSE);
 923         if (dtrec == NULL) {
 924                 /* exception thrown */
 925                 dd_free_datastore_t(&datastore);
 926                 return;
 927         }
 928 
 929         /* Open the dhcptab */
 930         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB,
 931                 DT_DHCPTAB, DSVC_WRITE);
 932 
 933         dd_free_datastore_t(&datastore);
 934         if (rcode != DSVC_SUCCESS) {
 935                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 936                 free_dtrec(dtrec);
 937                 return;
 938         }
 939 
 940         /* Delete the record */
 941         rcode = delete_dd_entry(handle, dtrec);
 942 
 943         (void) close_dd(&handle);
 944         if (rcode != DSVC_SUCCESS) {
 945                 throw_delete_dd_entry_exception(env, rcode, dtrec->dt_key);
 946         }
 947 
 948         free_dtrec(dtrec);
 949 }
 950 
 951 /*
 952  * Create the dhcptab.
 953  */
 954 /*ARGSUSED*/
 955 JNIEXPORT void JNICALL
 956 Java_com_sun_dhcpmgr_bridge_Bridge_createDhcptab(
 957     JNIEnv *env,
 958     jobject obj,
 959     jobject jdatastore)
 960 {
 961         dsvc_handle_t handle;
 962         dsvc_datastore_t datastore;
 963         int rcode;
 964 
 965         /* Create a dsvc_datastore_t using args and DHCP config settings */
 966         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
 967                 /* exception thrown */
 968                 return;
 969         }
 970 
 971         /* Open the dhcptab and in the process create it */
 972         rcode = open_dd(&handle, &datastore, DSVC_DHCPTAB, DT_DHCPTAB,
 973                 DSVC_CREATE | DSVC_READ | DSVC_WRITE);
 974 
 975         dd_free_datastore_t(&datastore);
 976 
 977         /*
 978          * If open was successful, then close. Otherwise, if unsuccessful
 979          * opening table, then map error to exception.
 980          */
 981         if (rcode == DSVC_SUCCESS) {
 982                 (void) close_dd(&handle);
 983         } else {
 984                 throw_open_dd_exception(env, rcode, DT_DHCPTAB);
 985         }
 986 }
 987 
 988 /*
 989  * Delete the dhcptab.
 990  */
 991 /*ARGSUSED*/
 992 JNIEXPORT void JNICALL
 993 Java_com_sun_dhcpmgr_bridge_Bridge_deleteDhcptab(
 994     JNIEnv *env,
 995     jobject obj,
 996     jobject jdatastore)
 997 {
 998         dsvc_datastore_t datastore;
 999         int rcode;
1000 
1001         /* Create a dsvc_datastore_t using args and DHCP config settings */
1002         if (!dd_make_datastore_t(env, &datastore, jdatastore)) {
1003                 /* exception thrown */
1004                 return;
1005         }
1006 
1007         rcode = remove_dd(&datastore, DSVC_DHCPTAB, DT_DHCPTAB);
1008 
1009         if (rcode != DSVC_SUCCESS) {
1010                 throw_remove_dd_exception(env, rcode, DT_DHCPTAB);
1011         }
1012 
1013         dd_free_datastore_t(&datastore);
1014 }