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 (c) 2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This module contains the private layer API. 31 */ 32 33 #include <stdio.h> 34 #include <assert.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <string.h> 38 #include <sys/param.h> 39 #include <libelf.h> 40 #include <gelf.h> 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <netinet/in.h> 44 #include <arpa/inet.h> 45 #include <dlfcn.h> 46 #include <glob.h> 47 #include <fcntl.h> 48 #include <libinetutil.h> 49 #include <dhcp_svc_public.h> 50 #include <dhcp_svc_private.h> 51 52 /* 53 * Threading notes for private layer consumers: 54 * 55 * The handles returned from open_dd() may be shared across multiple 56 * threads with no adverse side effects. However, it's up to that consumer 57 * to ensure that all threads have finished using an instance before 58 * closing the instance or removing the container it's referencing. 59 * Phrased differently: 60 * 61 * * Consumers must ensure all threads sharing a handle are 62 * finished before calling close_dd(). 63 * 64 * * Consumers must ensure all threads referencing a container are 65 * closed before calling remove_dd(). 66 */ 67 68 static boolean_t validate_dd_entry(dsvc_handle_t, const void *, boolean_t); 69 static int synch_init(dsvc_handle_t, const char *, uint_t); 70 static void synch_fini(dsvc_handle_t); 71 72 /* 73 * Order here should match the function array in <dhcp_svc_private.h> 74 */ 75 static char *funcnames[] = { 76 "status", "version", "mklocation", 77 "list_dt", "open_dt", "close_dt", "remove_dt", 78 "lookup_dt", "add_dt", "modify_dt", "delete_dt", 79 "list_dn", "open_dn", "close_dn", "remove_dn", 80 "lookup_dn", "add_dn", "modify_dn", "delete_dn" 81 }; 82 83 extern dsvc_synch_ops_t dsvcd_synch_ops; 84 85 /* 86 * Retrieve the current version associated with the datastore named by 87 * `resource' and store in `converp'. One might think we could do this via 88 * a simple readlink(2), but on internal release builds $(ROOTLINKS) 89 * installs using hardlinks, not symlinks. For this reason and to make it 90 * harder for us to be fooled, we'll dredge up the actual soname through 91 * ELF. Close your eyes, it's gonna get ugly. 92 */ 93 static int 94 get_conver(const char *resource, int *converp) 95 { 96 int elf_fd; 97 int i; 98 GElf_Shdr gelf_shdr; 99 GElf_Dyn gelf_dyn; 100 Elf_Scn *elf_scn = NULL; 101 Elf *elf_file; 102 Elf_Data *elf_data; 103 char *soname = NULL; 104 char path[MAXPATHLEN]; 105 106 (void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT, 107 DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, resource); 108 109 elf_fd = open(path, O_RDONLY); 110 if (elf_fd == -1) 111 return (DSVC_MODULE_ERR); 112 113 if (elf_version(EV_CURRENT) == EV_NONE) { 114 (void) close(elf_fd); 115 return (DSVC_INTERNAL); 116 } 117 118 elf_file = elf_begin(elf_fd, ELF_C_READ, NULL); 119 if (elf_file == NULL || elf_kind(elf_file) != ELF_K_ELF) { 120 (void) close(elf_fd); 121 return (DSVC_INTERNAL); 122 } 123 124 while ((elf_scn = elf_nextscn(elf_file, elf_scn)) != NULL) { 125 if (gelf_getshdr(elf_scn, &gelf_shdr) == 0) 126 continue; 127 128 if (gelf_shdr.sh_type != SHT_DYNAMIC) 129 continue; 130 131 elf_data = elf_getdata(elf_scn, NULL); 132 if (elf_data == NULL) 133 continue; 134 135 i = 0; 136 do { 137 (void) gelf_getdyn(elf_data, i++, &gelf_dyn); 138 if (gelf_dyn.d_tag == DT_SONAME) 139 soname = elf_strptr(elf_file, gelf_shdr.sh_link, 140 gelf_dyn.d_un.d_ptr); 141 } while (gelf_dyn.d_tag != DT_NULL && soname == NULL); 142 } 143 if (soname == NULL || sscanf(soname, "%*[^.].so.%d", converp) != 1) { 144 (void) elf_end(elf_file); 145 (void) close(elf_fd); 146 return (DSVC_MODULE_ERR); 147 } 148 (void) elf_end(elf_file); 149 (void) close(elf_fd); 150 151 return (DSVC_SUCCESS); 152 } 153 154 /* 155 * Unload a public datastore module. 156 */ 157 static int 158 unload_public_module(void **instance, dsvc_splapi_t *api) 159 { 160 static dsvc_splapi_t null_api; 161 162 if (dlclose(*instance) != 0) 163 return (DSVC_MODULE_UNLOAD_ERR); 164 165 *instance = NULL; 166 *api = null_api; 167 168 return (DSVC_SUCCESS); 169 } 170 171 /* 172 * Load public datastore module. Validates version of module. Returns 173 * instance of opened module, and populates the api argument with the 174 * function addresses exporting the API. 175 */ 176 static int 177 load_public_module(dsvc_datastore_t *ddp, void **instance, dsvc_splapi_t *api) 178 { 179 int i, v; 180 dsvc_splfuncp_t configure; 181 char path[MAXPATHLEN]; 182 183 (void) snprintf(path, sizeof (path), "%s%s/%s_%s.so", DHCP_CONFOPT_ROOT, 184 DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX, ddp->d_resource); 185 186 if (ddp->d_conver != DSVC_CUR_CONVER) 187 (void) snprintf(path, sizeof (path), "%s.%d", path, 188 ddp->d_conver); 189 190 *instance = dlopen(path, RTLD_LAZY|RTLD_GROUP|RTLD_WORLD); 191 if (*instance == NULL) 192 return (DSVC_MODULE_LOAD_ERR); 193 194 /* 195 * No requirement to duplicate the names - we can always reference 196 * the same set. 197 */ 198 api->version = (dsvc_splfuncp_t)dlsym(*instance, "version"); 199 if (api->version == NULL || api->version(&v) != DSVC_SUCCESS || 200 v != DSVC_PUBLIC_VERSION) { 201 (void) unload_public_module(instance, api); 202 return (DSVC_MODULE_VERSION); 203 } 204 205 configure = (dsvc_splfuncp_t)dlsym(*instance, "configure"); 206 if (configure != NULL) { 207 if (configure(ddp->d_config) != DSVC_SUCCESS) { 208 (void) unload_public_module(instance, api); 209 return (DSVC_MODULE_CFG_ERR); 210 } 211 } 212 213 for (i = 0; i < DSVC_NSPLFUNCS; i++) { 214 if ((((dsvc_splfuncp_t *)api)[i] = 215 (dsvc_splfuncp_t)dlsym(*instance, funcnames[i])) == NULL) { 216 (void) unload_public_module(instance, api); 217 return (DSVC_MODULE_ERR); 218 } 219 } 220 221 /* 222 * Caller requested the current version; fill in what that current 223 * version is. 224 */ 225 if (ddp->d_conver == DSVC_CUR_CONVER) { 226 int error; 227 error = get_conver(ddp->d_resource, &ddp->d_conver); 228 if (error != DSVC_SUCCESS) { 229 (void) unload_public_module(instance, api); 230 return (error); 231 } 232 } 233 234 return (DSVC_SUCCESS); 235 } 236 237 /* 238 * Return a dynamically-allocated null-terminated list of the available 239 * modules stored in the module directory. A count of the available 240 * modules is stored in the num argument. Caller is responsible for 241 * freeing the list. 242 */ 243 int 244 enumerate_dd(char ***modules, int *nump) 245 { 246 int i, retval; 247 char *ptr; 248 glob_t globbuf; 249 char globpat[MAXPATHLEN]; 250 251 if (modules == NULL || nump == NULL) 252 return (DSVC_INVAL); 253 254 (void) snprintf(globpat, sizeof (globpat), "%s%s/%s_*\\.so", 255 DHCP_CONFOPT_ROOT, DSVC_MODULE_DIR, DSVC_PUBLIC_PREFIX); 256 257 retval = glob(globpat, GLOB_NOSORT, NULL, &globbuf); 258 if (retval != 0) { 259 globfree(&globbuf); 260 switch (retval) { 261 case GLOB_NOMATCH: 262 *nump = 0; 263 *modules = NULL; 264 return (DSVC_SUCCESS); 265 case GLOB_NOSPACE: 266 return (DSVC_NO_MEMORY); 267 default: 268 return (DSVC_INTERNAL); 269 } 270 } 271 272 *modules = calloc(globbuf.gl_pathc, sizeof (char **)); 273 if (*modules == NULL) { 274 globfree(&globbuf); 275 return (DSVC_NO_MEMORY); 276 } 277 278 for (i = 0; i < globbuf.gl_pathc; i++) { 279 ptr = strrchr(globbuf.gl_pathv[i], '/'); 280 if (ptr == NULL) 281 ptr = globbuf.gl_pathv[i]; 282 else 283 ptr++; 284 (*modules)[i] = malloc(strlen(ptr) + 1); 285 if ((*modules)[i] == NULL) { 286 while (i--) 287 free((*modules)[i]); 288 free(modules); 289 globfree(&globbuf); 290 return (DSVC_NO_MEMORY); 291 } 292 293 (void) sscanf(ptr, "%*[^_]_%[^.]", (*modules)[i]); 294 } 295 296 globfree(&globbuf); 297 *nump = i; 298 return (DSVC_SUCCESS); 299 } 300 301 /* 302 * Check the status of the underlying service supporting the data store. 303 * Caller is responsible for freeing any dynamically allocated arguments. 304 */ 305 int 306 status_dd(dsvc_datastore_t *ddp) 307 { 308 void *instance; 309 dsvc_splapi_t api; 310 int error; 311 312 error = load_public_module(ddp, &instance, &api); 313 if (error != DSVC_SUCCESS) 314 return (error); 315 316 error = api.status(ddp->d_location); 317 318 (void) unload_public_module(&instance, &api); 319 320 return (error); 321 } 322 323 /* 324 * Create within the data store the "location" where containers will be 325 * stored. 326 */ 327 int 328 mklocation_dd(dsvc_datastore_t *ddp) 329 { 330 void *instance; 331 dsvc_splapi_t api; 332 int error; 333 334 error = load_public_module(ddp, &instance, &api); 335 if (error != DSVC_SUCCESS) 336 return (error); 337 338 error = api.mklocation(ddp->d_location); 339 340 (void) unload_public_module(&instance, &api); 341 342 return (error); 343 } 344 345 /* 346 * Return a list of the current container objects of type 'type' located at 347 * 'location' in listppp. Return the number of list elements in 'count'. 348 */ 349 int 350 list_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, char ***listppp, 351 uint_t *count) 352 { 353 void *instance; 354 dsvc_splapi_t api; 355 int error; 356 357 error = load_public_module(ddp, &instance, &api); 358 if (error != DSVC_SUCCESS) 359 return (error); 360 361 if (type == DSVC_DHCPTAB) 362 error = api.list_dt(ddp->d_location, listppp, count); 363 else 364 error = api.list_dn(ddp->d_location, listppp, count); 365 366 (void) unload_public_module(&instance, &api); 367 368 return (error); 369 } 370 371 /* 372 * Creates or opens the DHCP container of type called name within the 373 * specific datastore referenced by ddp, and returns a handle to this 374 * container in the handp argument. New containers are created with 375 * the identity of the caller. Caller is responsible for freeing any 376 * dynamically allocated arguments. The returned handle instance must 377 * be released by calling close_dd(). 378 */ 379 int 380 open_dd(dsvc_handle_t *handp, dsvc_datastore_t *ddp, dsvc_contype_t type, 381 const char *name, uint_t flags) 382 { 383 int error; 384 dsvc_handle_t hp; 385 386 *handp = NULL; 387 388 if (type == DSVC_DHCPNETWORK && name == NULL) 389 return (DSVC_INVAL); 390 391 if (flags & DSVC_CREATE && (flags & DSVC_WRITE) == 0) 392 return (DSVC_INVAL); 393 394 if ((hp = calloc(1, sizeof (struct dsvc_handle))) == NULL) 395 return (DSVC_NO_MEMORY); 396 397 if (type == DSVC_DHCPNETWORK) { 398 hp->d_conid.c_net.s_addr = ntohl(inet_addr(name)); 399 if (hp->d_conid.c_net.s_addr == INADDR_BROADCAST) { 400 free(hp); 401 return (DSVC_INVAL); 402 } 403 get_netmask4(&hp->d_conid.c_net, &hp->d_conid.c_mask); 404 } 405 406 error = load_public_module(ddp, &hp->d_instance, &hp->d_api); 407 if (error != DSVC_SUCCESS) { 408 free(hp); 409 return (error); 410 } 411 412 hp->d_type = type; 413 hp->d_desc.d_conver = ddp->d_conver; 414 hp->d_desc.d_resource = strdup(ddp->d_resource); 415 hp->d_desc.d_location = strdup(ddp->d_location); 416 if (hp->d_desc.d_resource == NULL || hp->d_desc.d_location == NULL) { 417 error = DSVC_NO_MEMORY; 418 goto error; 419 } 420 421 /* 422 * Initialize the synchronization strategy (may not be any). 423 */ 424 error = synch_init(hp, name, flags); 425 if (error != DSVC_SUCCESS) 426 goto error; 427 428 if (type == DSVC_DHCPTAB) 429 error = hp->d_api.open_dt(&hp->d_hand, ddp->d_location, flags); 430 else 431 error = hp->d_api.open_dn(&hp->d_hand, ddp->d_location, flags, 432 &hp->d_conid.c_net, &hp->d_conid.c_mask); 433 434 if (error != DSVC_SUCCESS) { 435 if (hp->d_synch != NULL) 436 synch_fini(hp); 437 goto error; 438 } 439 440 *handp = hp; 441 return (DSVC_SUCCESS); 442 error: 443 (void) unload_public_module(&hp->d_instance, &hp->d_api); 444 free(hp->d_desc.d_resource); 445 free(hp->d_desc.d_location); 446 free(hp); 447 return (error); 448 } 449 450 /* 451 * Remove DHCP container called name of type within the specific datastore 452 * referenced by ddp. Caller is responsible for freeing any dynamically 453 * allocated arguments. 454 */ 455 int 456 remove_dd(dsvc_datastore_t *ddp, dsvc_contype_t type, const char *name) 457 { 458 void *instance; 459 int error; 460 dsvc_splapi_t api; 461 struct in_addr ip, mask; 462 463 if (type != DSVC_DHCPTAB) { 464 if ((ip.s_addr = inet_addr(name)) == INADDR_BROADCAST) 465 return (DSVC_INVAL); 466 ip.s_addr = ntohl(ip.s_addr); 467 get_netmask4(&ip, &mask); 468 } 469 470 error = load_public_module(ddp, &instance, &api); 471 if (error != DSVC_SUCCESS) 472 return (error); 473 474 /* remove the DHCP container */ 475 if (type == DSVC_DHCPTAB) 476 error = api.remove_dt(ddp->d_location); 477 else 478 error = api.remove_dn(ddp->d_location, &ip, &mask); 479 480 (void) unload_public_module(&instance, &api); 481 482 return (error); 483 } 484 485 /* 486 * Delete the handle instance referenced by hand. Frees hand if the close 487 * operation was successful. NOTE: Caller is responsible for synchronizing 488 * multiple threads such that close_dd() is called when all consuming 489 * threads have exited. 490 */ 491 int 492 close_dd(dsvc_handle_t *handp) 493 { 494 int error; 495 496 if (handp == NULL || DSVC_HANDLE_INVAL(*handp)) 497 return (DSVC_INVAL); 498 499 if ((*handp)->d_type == DSVC_DHCPTAB) 500 error = (*handp)->d_api.close_dt(&((*handp)->d_hand)); 501 else 502 error = (*handp)->d_api.close_dn(&((*handp)->d_hand)); 503 504 if (error == DSVC_SUCCESS) { 505 error = unload_public_module(&(*handp)->d_instance, 506 &(*handp)->d_api); 507 if ((*handp)->d_synch != NULL) 508 synch_fini(*handp); 509 free((*handp)->d_desc.d_resource); 510 free((*handp)->d_desc.d_location); 511 free(*handp); 512 *handp = NULL; 513 } 514 515 return (error); 516 } 517 518 /* 519 * Searches hand container for records that match the query described by 520 * the combination of query and targetp. If the partial field is true, then 521 * lookup operations that have located some records but are unable to 522 * complete entirely are allowed. The query argument consists of 2 fields, 523 * each 16 bits long. The lower 16 bits selects which fields in the targetp 524 * record are to be considered in the query. The upper 16 bits identifies 525 * whether a particular field value must match (bit set) or not match (bit 526 * clear). Unused bits in both 16 bit fields must be 0. The count argument 527 * specifies the maximum number of matching records to return. A count 528 * value of -1 requests that all matching records be returned. recordsp is 529 * set to point to the resulting list of records; if recordsp is NULL then 530 * no records are actually returned. Note that these records are 531 * dynamically allocated, thus the caller is responsible for freeing them. 532 * The number of records found is returned in nrecordsp; a value of 0 means 533 * that no records matched the query. 534 */ 535 int 536 lookup_dd(dsvc_handle_t hand, boolean_t partial, uint_t query, 537 int count, const void *targetp, void **recordsp, uint_t *nrecordsp) 538 { 539 uint_t mask = 0; 540 int error; 541 void *unlock_cookie; 542 int (*lookup)(); 543 544 if (targetp == NULL || nrecordsp == NULL || DSVC_HANDLE_INVAL(hand)) 545 return (DSVC_INVAL); 546 547 if (hand->d_type == DSVC_DHCPTAB) { 548 mask = (uint_t)~DT_QALL; 549 lookup = hand->d_api.lookup_dt; 550 } else { 551 mask = (uint_t)~DN_QALL; 552 lookup = hand->d_api.lookup_dn; 553 } 554 555 /* validate query */ 556 if (((query & 0xffff) & mask) || ((query >> 16) & mask)) 557 return (DSVC_INVAL); 558 559 /* 560 * XXX: need to validate the `targetp' -- what a mess cuz only the 561 * fields lit in `query' need to be valid. 562 */ 563 564 if (hand->d_synch != NULL) { 565 error = DSVC_SYNCH_RDLOCK(hand->d_synch, &unlock_cookie); 566 if (error != DSVC_SUCCESS) 567 return (error); 568 } 569 570 error = lookup(hand->d_hand, partial, query, count, targetp, recordsp, 571 nrecordsp); 572 573 if (hand->d_synch != NULL) 574 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie); 575 576 return (error); 577 } 578 579 /* 580 * Frees the record pointed to by entryp. 581 */ 582 void 583 free_dd(dsvc_handle_t hand, void *entryp) 584 { 585 if (DSVC_HANDLE_INVAL(hand) || entryp == NULL) 586 return; 587 588 if (hand->d_type == DSVC_DHCPTAB) 589 free_dtrec((dt_rec_t *)entryp); 590 else 591 free_dnrec((dn_rec_t *)entryp); 592 } 593 594 /* 595 * Frees the list of records pointed to by listp. 596 */ 597 void 598 free_dd_list(dsvc_handle_t hand, void *listp) 599 { 600 if (DSVC_HANDLE_INVAL(hand) || listp == NULL) 601 return; 602 603 if (hand->d_type == DSVC_DHCPTAB) 604 free_dtrec_list((dt_rec_list_t *)listp); 605 else 606 free_dnrec_list((dn_rec_list_t *)listp); 607 } 608 609 /* 610 * Add the record newp to the DHCP container hand. newp's update signature 611 * will be updated by the public layer module doing the update. Caller is 612 * responsible for freeing newp if it was dynamically allocated. 613 */ 614 int 615 add_dd_entry(dsvc_handle_t hand, void *newp) 616 { 617 int error; 618 void *unlock_cookie; 619 620 if (DSVC_HANDLE_INVAL(hand)) 621 return (DSVC_INVAL); 622 623 if (!validate_dd_entry(hand, newp, B_FALSE)) 624 return (DSVC_INVAL); 625 626 if (hand->d_synch != NULL) { 627 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie); 628 if (error != DSVC_SUCCESS) 629 return (error); 630 } 631 632 if (hand->d_type == DSVC_DHCPTAB) 633 error = hand->d_api.add_dt(hand->d_hand, newp); 634 else 635 error = hand->d_api.add_dn(hand->d_hand, newp); 636 637 if (hand->d_synch != NULL) 638 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie); 639 640 return (error); 641 } 642 643 /* 644 * Modify the record origp with the record newp in the DHCP container hand. 645 * newp's update signature will be updated by the public layer module doing 646 * the update. Caller is responsible for freeing origp and/or newp if they 647 * were dynamically allocated. 648 */ 649 int 650 modify_dd_entry(dsvc_handle_t hand, const void *origp, void *newp) 651 { 652 int error; 653 void *unlock_cookie; 654 655 if (DSVC_HANDLE_INVAL(hand)) 656 return (DSVC_INVAL); 657 658 if (!validate_dd_entry(hand, origp, B_TRUE)) 659 return (DSVC_INVAL); 660 661 if (!validate_dd_entry(hand, newp, B_FALSE)) 662 return (DSVC_INVAL); 663 664 if (hand->d_synch != NULL) { 665 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie); 666 if (error != DSVC_SUCCESS) 667 return (error); 668 } 669 670 if (hand->d_type == DSVC_DHCPTAB) 671 error = hand->d_api.modify_dt(hand->d_hand, origp, newp); 672 else 673 error = hand->d_api.modify_dn(hand->d_hand, origp, newp); 674 675 if (hand->d_synch != NULL) 676 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie); 677 678 return (error); 679 } 680 681 /* 682 * Deletes the record referred to by entryp from the DHCP container hand. 683 * Caller is responsible for freeing entryp if it was dynamically 684 * allocated. 685 */ 686 int 687 delete_dd_entry(dsvc_handle_t hand, void *entryp) 688 { 689 int error; 690 void *unlock_cookie; 691 692 if (DSVC_HANDLE_INVAL(hand)) 693 return (DSVC_INVAL); 694 695 if (!validate_dd_entry(hand, entryp, B_TRUE)) 696 return (DSVC_INVAL); 697 698 if (hand->d_synch != NULL) { 699 error = DSVC_SYNCH_WRLOCK(hand->d_synch, &unlock_cookie); 700 if (error != DSVC_SUCCESS) 701 return (error); 702 } 703 704 if (hand->d_type == DSVC_DHCPTAB) 705 error = hand->d_api.delete_dt(hand->d_hand, entryp); 706 else 707 error = hand->d_api.delete_dn(hand->d_hand, entryp); 708 709 if (hand->d_synch != NULL) 710 (void) DSVC_SYNCH_UNLOCK(hand->d_synch, unlock_cookie); 711 712 return (error); 713 } 714 715 /* 716 * Validate that the DHCP network record `dn' is correctly formed; returns 717 * B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only 718 * validate the key. 719 */ 720 static boolean_t 721 validate_dnrec(dsvc_handle_t hand, const dn_rec_t *dn, boolean_t justkey) 722 { 723 /* CIP must be on container's network */ 724 if (hand->d_conid.c_net.s_addr != 725 (dn->dn_cip.s_addr & hand->d_conid.c_mask.s_addr)) 726 return (B_FALSE); 727 728 if (justkey) 729 return (B_TRUE); 730 731 if (dn->dn_cid_len < 1 || dn->dn_cid_len > DN_MAX_CID_LEN) 732 return (B_FALSE); 733 734 if ((dn->dn_flags & ~DN_FALL) != 0) 735 return (B_FALSE); 736 737 return (B_TRUE); 738 } 739 740 /* 741 * Validate that the dhcptab record `dt' is correctly formed; returns 742 * B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then only 743 * validate the key. 744 */ 745 /* ARGSUSED */ 746 static boolean_t 747 validate_dtrec(dsvc_handle_t hand, const dt_rec_t *dt, boolean_t justkey) 748 { 749 return (dt->dt_type == DT_SYMBOL || dt->dt_type == DT_MACRO); 750 } 751 752 /* 753 * Validate that a DHCP record of type `hand->d_type' is correctly formed; 754 * returns B_TRUE if it is, B_FALSE if it's not. If `justkey' is set, then 755 * only validate the key. 756 */ 757 static boolean_t 758 validate_dd_entry(dsvc_handle_t hand, const void *entryp, boolean_t justkey) 759 { 760 if (entryp == NULL) 761 return (B_FALSE); 762 763 if (hand->d_type == DSVC_DHCPTAB) 764 return (validate_dtrec(hand, (dt_rec_t *)entryp, justkey)); 765 else if (hand->d_type == DSVC_DHCPNETWORK) 766 return (validate_dnrec(hand, (dn_rec_t *)entryp, justkey)); 767 768 return (B_FALSE); 769 } 770 771 /* 772 * Get the type of synchronization needed for this module and store in 773 * `synchtypep'. Returns a DSVC_* code. This function is exported so that 774 * dsvclockd(1M) can use it. 775 */ 776 int 777 module_synchtype(dsvc_datastore_t *ddp, dsvc_synchtype_t *synchtypep) 778 { 779 void *instance; 780 dsvc_splapi_t api; 781 dsvc_synchtype_t *dsvc_synchtypep; 782 783 if (load_public_module(ddp, &instance, &api) != DSVC_SUCCESS) 784 return (DSVC_INTERNAL); 785 786 dsvc_synchtypep = dlsym(instance, "dsvc_synchtype"); 787 if (dsvc_synchtypep != NULL) 788 *synchtypep = *dsvc_synchtypep; 789 else 790 *synchtypep = DSVC_SYNCH_NONE; 791 792 (void) unload_public_module(&instance, &api); 793 794 return (DSVC_SUCCESS); 795 } 796 797 /* 798 * Initialize private-layer synchronization on handle `hand' for container 799 * `conname'; `flags' is the same flags passed into open_dd(). If there's 800 * no synchronization needed, always succeeds. Returns a DSVC_* code. 801 */ 802 int 803 synch_init(dsvc_handle_t hand, const char *conname, uint_t flags) 804 { 805 dsvc_synchtype_t synchtype; 806 dsvc_synch_t *sp; 807 int error; 808 int (*mkloctoken)(const char *, char *, size_t); 809 810 error = module_synchtype(&hand->d_desc, &synchtype); 811 if (error != DSVC_SUCCESS) 812 return (error); 813 814 if (synchtype == DSVC_SYNCH_NONE) 815 return (DSVC_SUCCESS); 816 817 sp = malloc(sizeof (dsvc_synch_t)); 818 if (sp == NULL) 819 return (DSVC_NO_MEMORY); 820 821 sp->s_conname = strdup(conname); 822 if (sp->s_conname == NULL) { 823 free(sp); 824 return (DSVC_NO_MEMORY); 825 } 826 sp->s_nonblock = flags & DSVC_NONBLOCK; 827 sp->s_datastore = &hand->d_desc; 828 829 mkloctoken = (int (*)())dlsym(hand->d_instance, "mkloctoken"); 830 if (mkloctoken == NULL) { 831 (void) strlcpy(sp->s_loctoken, sp->s_datastore->d_location, 832 sizeof (sp->s_loctoken)); 833 } else { 834 error = mkloctoken(sp->s_datastore->d_location, sp->s_loctoken, 835 sizeof (sp->s_loctoken)); 836 if (error != DSVC_SUCCESS) { 837 free(sp->s_conname); 838 free(sp); 839 return (error); 840 } 841 } 842 843 /* 844 * The only synchtype supported is DSVC_SYNCH_DSVCD; if this 845 * changes, we'll need to enhance this. 846 */ 847 assert((synchtype & DSVC_SYNCH_STRATMASK) == DSVC_SYNCH_DSVCD); 848 sp->s_ops = &dsvcd_synch_ops; 849 850 error = DSVC_SYNCH_INIT(sp, synchtype & DSVC_SYNCH_FLAGMASK); 851 if (error != DSVC_SUCCESS) { 852 free(sp->s_conname); 853 free(sp); 854 return (error); 855 } 856 857 hand->d_synch = sp; 858 return (DSVC_SUCCESS); 859 } 860 861 /* 862 * Finish using private-layer synchronization on handle `hand'. 863 */ 864 void 865 synch_fini(dsvc_handle_t hand) 866 { 867 DSVC_SYNCH_FINI(hand->d_synch); 868 free(hand->d_synch->s_conname); 869 free(hand->d_synch); 870 hand->d_synch = NULL; 871 }