1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** rpcdepdb.c 82** 83** FACILITY: 84** 85** RPC Daemon 86** 87** ABSTRACT: 88** 89** Generic Endpoint Database Management, Forwarding, 90** and Lookup Routines 91** 92** 93*/ 94 95#include <commonp.h> 96#include <com.h> 97#include <comp.h> 98 99#include <dce/ep.h> /* derived from ep.idl */ 100#include <dce/mgmt.h> /* derived from mgmt.idl */ 101#include <dsm.h> /* derived from dsm.idl */ 102 103#include <rpcdp.h> 104#include <rpcddb.h> 105#include <rpcdepdb.h> 106#include <rpcdepdbp.h> 107#include <rpcdutil.h> 108 109#include <comtwr.h> 110 111/* 112 * The server supports a single endpoint location database. 113 */ 114INTERNAL epdb_handle_t epdb_handle = NULL; 115 116/* 117 * The current version of the persistent database file (the value in a file_hdr). 118 */ 119#define epdb_c_file_version 8 120 121INTERNAL void epdb_recreate_lists 122 ( 123 struct db *h, 124 error_status_t *status 125 ); 126 127INTERNAL void epdb_chk_entry 128 ( 129 ept_entry_p_t xentry, 130 twr_fields_p_t tfp, 131 rpc_addr_p_t addr, 132 error_status_t *status 133 ); 134 135INTERNAL void epdb_chk_map_entry 136 ( 137 twr_fields_p_t tfp, 138 error_status_t *status 139 ); 140 141INTERNAL void epdb_to_ept 142 ( 143 db_entry_p_t entp, 144 ept_entry_t *xentry, 145 error_status_t *status 146 ); 147 148INTERNAL void epdb_insert_entry 149 ( 150 struct db *h, 151 ept_entry_p_t xentry, 152 twr_fields_p_t tfp, 153 rpc_addr_p_t addr, 154 db_entry_p_t *entp, 155 error_status_t *status 156 ); 157 158INTERNAL void epdb_replace_entry 159 ( 160 struct db *h, 161 ept_entry_p_t xentry, 162 db_entry_p_t entp, 163 error_status_t *status 164 ); 165 166INTERNAL boolean32 epdb_is_replace_candidate 167 ( 168 db_entry_t *entp, 169 uuid_p_t object, 170 twr_fields_p_t tfp, 171 rpc_addr_p_t addr 172 ); 173 174INTERNAL void epdb_delete_replaceable_entries 175 ( 176 struct db *h, 177 uuid_p_t object, 178 twr_fields_p_t tfp, 179 rpc_addr_p_t addr, 180 error_status_t *status 181 ); 182 183INTERNAL void epdb_delete_entries_by_obj_if_addr 184 ( 185 struct db *h, 186 boolean32 object_speced, 187 uuid_p_t object, 188 rpc_if_id_p_t interface, 189 rpc_addr_p_t addr, 190 error_status_t *status 191 ); 192 193INTERNAL db_entry_t *epdb_lookup_entry 194 ( 195 struct db *h, 196 ept_entry_p_t xentry 197 ); 198 199INTERNAL void lookup 200 ( 201 struct db *h, 202 unsigned32 inquiry_type, 203 uuid_p_t object, 204 rpc_if_id_p_t interface, 205 unsigned32 vers_option, 206 ept_lookup_handle_t *entry_handle, 207 unsigned32 max_ents, 208 unsigned32 *num_ents, 209 ept_entry_t entries[], 210 error_status_t *status 211 ); 212 213INTERNAL void lookup_match 214 ( 215 unsigned32 inquiry_type, 216 uuid_p_t object, 217 rpc_if_id_p_t interface, 218 unsigned32 vers_option, 219 unsigned32 max_ents, 220 unsigned32 *num_ents, 221 ept_entry_t entries[], 222 unsigned32 list_type, 223 db_lists_t **lpp, 224 error_status_t *status 225 ); 226 227INTERNAL void map 228 ( 229 struct db *h, 230 uuid_p_t object, 231 rpc_if_id_p_t interface, 232 rpc_syntax_id_p_t data_rep, 233 rpc_protocol_id_t rpc_protocol, 234 unsigned32 rpc_protocol_vers_major, 235 unsigned32 rpc_protocol_vers_minor, 236 rpc_protseq_id_t protseq, 237 ept_lookup_handle_t *map_handle, 238 unsigned32 max_ents, 239 unsigned32 *n_ents, 240 db_entry_t *db_entries[], 241 unsigned32 *status 242 ); 243 244INTERNAL void map_match 245 ( 246 uuid_p_t object, 247 rpc_if_id_p_t interface, 248 rpc_syntax_id_p_t data_rep, 249 rpc_protocol_id_t rpc_protocol, 250 unsigned32 rpc_protocol_vers_major, 251 unsigned32 rpc_protocol_vers_minor, 252 rpc_protseq_id_t protseq, 253 unsigned32 max_ents, 254 unsigned32 *n_ents, 255 db_entry_t *entries[], 256 ept_lookup_handle_t *map_handle, 257 unsigned32 pass, 258 db_list_type_t list, 259 db_lists_t **lpp, 260 unsigned32 *status 261 ); 262 263INTERNAL void map_mgmt 264 ( 265 struct db *h, 266 uuid_p_t object, 267 rpc_syntax_id_p_t data_rep, 268 rpc_protocol_id_t rpc_protocol, 269 unsigned32 rpc_protocol_vers_major, 270 unsigned32 rpc_protocol_vers_minor, 271 rpc_protseq_id_t protseq, 272 ept_lookup_handle_t *map_handle, 273 unsigned32 max_ents, 274 unsigned32 *n_ents, 275 db_entry_t *db_entries[], 276 unsigned32 *status 277 ); 278 279INTERNAL void map_mgmt_match 280 ( 281 uuid_p_t object, 282 rpc_syntax_id_p_t data_rep, 283 rpc_protocol_id_t rpc_protocol, 284 unsigned32 rpc_protocol_vers_major, 285 unsigned32 rpc_protocol_vers_minor, 286 rpc_protseq_id_t protseq, 287 unsigned32 max_ents, 288 unsigned32 *n_ents, 289 db_entry_t *entries[], 290 ept_lookup_handle_t *map_handle, 291 unsigned32 pass, 292 db_list_type_t list, 293 db_lists_t **lpp, 294 unsigned32 *status 295 ); 296 297INTERNAL boolean32 map_mgmt_endpt_unique 298 ( 299 rpc_addr_p_t addr, 300 unsigned32 n_ents, 301 db_entry_t *entries[] 302 ); 303 304 305/* 306 * Get an endpoint database handle from a handle_t. 307 * 308 * If the handle is not bound to an object (i.e. the object 309 * is nil) treat this as a request to just use "the" endpoint 310 * database. If a specific object is specified, make sure that 311 * the object is the same as the endpoint database object. 312 * (accept a null handle to allow for "local" callers). 313 */ 314PRIVATE void epdb_handle_from_ohandle(h, epdb_h, status) 315handle_t h; 316epdb_handle_t *epdb_h; 317error_status_t *status; 318{ 319 idl_uuid_t obj; 320 idl_uuid_t epdb_obj; 321 322 SET_STATUS(status, rpc_s_ok); 323 324 if (h == NULL) 325 { 326 *epdb_h = epdb_handle; 327 return; 328 } 329 330 rpc_binding_inq_object(h, &obj, status); 331 if (uuid_is_nil(&obj, status)) 332 *epdb_h = epdb_handle; 333 else 334 { 335 epdb_inq_object(epdb_handle, &epdb_obj, status); 336 if (uuid_equal(&obj, &epdb_obj, status)) 337 *epdb_h = epdb_handle; 338 else 339 SET_STATUS(status, ept_s_cant_perform_op); /* !!! ep_wrong_object? */ 340 } 341 return; 342} 343 344/* Return the handle to the ep database 345 * Since there's only one database just return what's in 346 * epdb_handle 347 */ 348PRIVATE epdb_handle_t epdb_inq_handle() 349{ 350 return(epdb_handle); 351} 352 353 354/* 355 * Open/create a database and return a handle to it. 356 * Init the database lists and lock. Start the task 357 * to check server liveness and to purge entries that 358 * are marked as deleted. 359 */ 360PRIVATE epdb_handle_t epdb_init(pathname, status) 361unsigned char *pathname; 362error_status_t *status; 363{ 364 struct db *h; 365 366 SET_STATUS_OK(status); 367 368 h = (struct db *) malloc(sizeof(struct db)); 369 if (h == NULL) { 370 SET_STATUS(status, ept_s_cant_perform_op); 371 return(NULL); 372 } 373 374 h->dsh = NULL; 375 376 db_init_lists(h); 377 378 db_open(h, pathname, epdb_c_file_version, status); 379 if (! STATUS_OK(status)) 380 { 381 /* Try deleting and recreating the database */ 382 unlink(pathname); 383 db_open(h, pathname, epdb_c_file_version, status); 384 if (! STATUS_OK(status)) 385 { 386 return NULL; 387 } 388 } 389 390 /* Database now exists, recreate its lists 391 */ 392 epdb_recreate_lists(h, status); 393 if (! STATUS_OK(status)) return(NULL); 394 395 db_init_lock(h); 396 397 sliv_init(h, status); 398 if (! STATUS_OK(status)) return(NULL); 399 400 epdb_handle = (epdb_handle_t) h; 401 402 return((epdb_handle_t) h); 403} 404 405INTERNAL void epdb_recreate_lists(h, status) 406struct db *h; 407error_status_t *status; 408{ 409 db_entry_t *entp = NULL; 410 dsm_marker_t marker; /* DSM datastore traversal marker */ 411 412 dsm_marker_reset(&marker); 413 414 while(true) 415 { 416 void* _entp = NULL; 417 dsm_read(h->dsh,&marker, &_entp,status); /* get next record */ 418 entp = (db_entry_t*) _entp; 419 if (! STATUS_OK(status)) 420 { 421 if (*status == dsm_err_no_more_entries) 422 { 423 SET_STATUS(status, error_status_ok); 424 } 425 else 426 { 427 if (dflag) 428 show_st("Error reading ept database", status); 429 SET_STATUS(status, ept_s_cant_access); 430 } 431 return; 432 } 433 434 tower_to_addr(&entp->tower, &entp->addr, status); 435 if (! STATUS_OK(status)) 436 { 437 if (dflag) 438 show_st("tower_to_addr error for ept entry", status); 439 440 SET_STATUS(status, ept_s_invalid_entry); 441 return; 442 } 443 444 entp->read_nrefs = 0; 445 entp->ncomm_fails = 0; 446 447 db_lists_add(h, entp); 448 } 449} 450 451 452/* 453 * epdb_chk_entry - check an entry that is about to be inserted 454 * into the ep database 455 * All tower floors in an entry must be valid and non-nil 456 * (eg. nil interface uuid is prohibited). Also, check tower 457 * via rpc_tower_to_binding - sliv tasks will need to get binding 458 * handle 459 */ 460INTERNAL void epdb_chk_entry(xentry, tfp, addr, status) 461ept_entry_p_t xentry; 462twr_fields_p_t tfp; 463rpc_addr_p_t addr; 464error_status_t *status; 465{ 466 rpc_binding_handle_t binding_h; 467 error_status_t tmp_st; 468 469 if (uuid_is_nil(&tfp->interface.uuid, &tmp_st) || 470 uuid_is_nil(&tfp->data_rep.id, &tmp_st) || 471 (addr == NULL) || 472 (addr->len == 0)) 473 { 474 SET_STATUS(status, ept_s_invalid_entry); 475 return; 476 } 477 478 rpc_tower_to_binding(xentry->tower->tower_octet_string, &binding_h, status); 479 if (! STATUS_OK(status)) return; 480 481 rpc_binding_free(&binding_h, &tmp_st); 482} 483 484INTERNAL void epdb_chk_map_entry(tfp, status) 485twr_fields_p_t tfp; 486error_status_t *status; 487{ 488 error_status_t tmp_st; 489 490 assert (status != NULL); 491 if (uuid_is_nil(&tfp->interface.uuid, &tmp_st) || 492 uuid_is_nil(&tfp->data_rep.id, &tmp_st) || 493 (! RPC_PROTSEQ_INQ_SUPPORTED(tfp->protseq)) ) 494 SET_STATUS(status, ept_s_invalid_entry); 495 else 496 SET_STATUS_OK(status); 497} 498 499INTERNAL void epdb_to_ept(entp, xentry, status) 500db_entry_p_t entp; 501ept_entry_t *xentry; 502error_status_t *status; 503{ 504 xentry->object = entp->object; 505 memcpy((char *)xentry->annotation, (char *)entp->annotation, 506 sizeof(xentry->annotation)); 507 508 tower_ss_copy(&entp->tower, &xentry->tower, status); 509} 510 511/* epdb_insert_entry 512 * Allocate dsm storage for an entry in the endpoint database 513 * Fill the entry from xentry, tfp, and addr 514 * Write it to disk 515 * Add entry to various lists 516 * Return db pointer to entry in entp 517 */ 518INTERNAL void epdb_insert_entry(h, xentry, tfp, addr, entp, status) 519struct db *h; 520ept_entry_p_t xentry; 521twr_fields_p_t tfp; 522rpc_addr_p_t addr; 523db_entry_p_t *entp; 524error_status_t *status; 525{ 526 db_entry_t *db_entp; 527 error_status_t tmp_st; 528 529 dsm_allocate(h->dsh, sizeof(db_entry_t) + xentry->tower->tower_length, 530 (void **) entp, status); 531 if (! STATUS_OK(status)) return; 532 533 db_entp = *entp; 534 535 db_entp->read_nrefs = 0; 536 db_entp->ncomm_fails = 0; 537 db_entp->delete_flag = false; 538 539 db_entp->object = xentry->object; 540 db_entp->interface = tfp->interface; 541 db_entp->object_nil = uuid_is_nil(&db_entp->object, &tmp_st); 542 db_entp->if_nil = uuid_is_nil(&db_entp->interface.uuid, &tmp_st); 543 db_entp->data_rep_id = tfp->data_rep.id; 544 db_entp->data_rep_vers_major = RPC_IF_VERS_MAJOR(tfp->data_rep.version); 545 db_entp->data_rep_vers_minor = RPC_IF_VERS_MINOR(tfp->data_rep.version); 546 db_entp->rpc_protocol = tfp->rpc_protocol; 547 db_entp->rpc_protocol_vers_major = tfp->rpc_protocol_vers_major; 548 db_entp->rpc_protocol_vers_minor = tfp->rpc_protocol_vers_minor; 549 db_entp->addr = addr; 550 memcpy((char *)db_entp->annotation, (char *)xentry->annotation, 551 sizeof(db_entp->annotation)); 552 db_entp->tower.tower_length = xentry->tower->tower_length; 553 memcpy((char *) db_entp->tower.tower_octet_string, (char *) xentry->tower->tower_octet_string, 554 xentry->tower->tower_length); 555 556 dsm_write(h->dsh, (void *) db_entp, status); 557 if (! STATUS_OK(status)) return; 558 559 db_lists_add(h, db_entp); 560} 561 562/* epdb_replace_entry 563 * Replace an existing entry - just change the annotation 564 * because all other fields are the same 565 * Also do some mgmt stuff - clear delete flag and ncomm_fails field 566 */ 567INTERNAL void epdb_replace_entry(h, xentry, entp, status) 568struct db *h; 569ept_entry_p_t xentry; 570db_entry_p_t entp; 571error_status_t *status; 572{ 573 entp->ncomm_fails = 0; 574 entp->delete_flag = false; 575 memcpy((char *)entp->annotation, (char *)xentry->annotation, 576 sizeof(entp->annotation)); 577 578 db_update_entry(h, entp, status); 579} 580 581/* epdb_delete_entry 582 * Delete an entry from the database. 583 * 584 * If any readers have unlocked the db but 585 * are pointing to this entry, mark the entry 586 * as deleted and write it to disk. 587 * Otherwise, remove the entry from all 588 * lists and delete it from the database 589 */ 590PRIVATE void epdb_delete_entry(h, entp, status) 591struct db *h; 592db_entry_p_t entp; 593error_status_t *status; 594{ 595 if (entp->read_nrefs == 0) 596 { 597 db_lists_remove(h, entp); 598 rpc__naf_addr_free(&entp->addr, status); 599 dsm_free(h->dsh, (void *) entp, status); 600 } 601 else 602 { 603 entp->delete_flag = true; 604 db_update_entry(h, entp, status); 605 } 606} 607 608/* 609 * epdb_is_replace_candidate 610 * 611 * Return true iff the specified entry looks like a candidate for 612 * replacement. Requirements for candidacy are: matching object, matching 613 * i/f UUID and major version, matching RPC protseq, matching data rep, 614 * matching RPC protocol ID and RPC protocol major and minor version. 615 * Candidacy is not sufficient to determine actual replaceability; i/f 616 * minor version and network address must be considered as well. See 617 * below. 618 */ 619INTERNAL boolean32 epdb_is_replace_candidate(entp, object, tfp, addr) 620twr_fields_p_t tfp; 621uuid_p_t object; 622db_entry_t *entp; 623rpc_addr_p_t addr; 624{ 625 error_status_t tmp_st; 626 unsigned32 data_rep_vers_major, 627 data_rep_vers_minor; 628 629 data_rep_vers_major = RPC_IF_VERS_MAJOR(tfp->data_rep.version); 630 data_rep_vers_minor = RPC_IF_VERS_MINOR(tfp->data_rep.version); 631 632 return (uuid_equal(object, &entp->object, &tmp_st) && 633 uuid_equal(&tfp->interface.uuid, &entp->interface.uuid, &tmp_st) && 634 (tfp->interface.vers_major == entp->interface.vers_major) && 635 (addr->rpc_protseq_id == entp->addr->rpc_protseq_id) && 636 uuid_equal(&tfp->data_rep.id, &entp->data_rep_id, &tmp_st) && 637 (data_rep_vers_major == entp->data_rep_vers_major) && 638 (data_rep_vers_minor == entp->data_rep_vers_minor) && 639 (tfp->rpc_protocol == entp->rpc_protocol) && 640 (tfp->rpc_protocol_vers_major == entp->rpc_protocol_vers_major) && 641 (tfp->rpc_protocol_vers_minor == entp->rpc_protocol_vers_minor)); 642} 643 644/* 645 * epdb_delete_replaceable_entries 646 * 647 * Delete entries which are "replaceable" by the new entry implied by 648 * the object, tfp, and addr parameters. 649 */ 650INTERNAL void epdb_delete_replaceable_entries(h, object, tfp, addr, status) 651struct db *h; 652uuid_p_t object; 653twr_fields_p_t tfp; 654rpc_addr_p_t addr; 655error_status_t *status; 656{ 657 unsigned_char_p_t netaddr, 658 netaddr2; 659 db_lists_t *lp, 660 *lp_first, 661 *lp_next; 662 db_list_type_t list_type; 663 error_status_t tmp_st; 664 665 rpc__naf_addr_inq_netaddr(addr, &netaddr, status); 666 if (! STATUS_OK(status)) 667 { 668 SET_STATUS(status, ept_s_invalid_entry); 669 return; 670 } 671 672 if (! uuid_is_nil(object, &tmp_st)) 673 { 674 list_type = db_c_object_list; 675 lp_first = db_list_first(&h->lists_mgmt, db_c_object_list, object); 676 } 677 else 678 { 679 list_type = db_c_interface_list; 680 lp_first = db_list_first(&h->lists_mgmt, db_c_interface_list, &tfp->interface.uuid); 681 } 682 683 /* 684 * Scan the list and see if there are any replace candidates with an 685 * i/f minor version that's greater than the proposed new entry. If 686 * there are, the replace must fail. 687 */ 688 for (lp = lp_first; lp != NULL; lp = db_list_next(list_type, lp)) 689 { 690 db_entry_t *entp = (db_entry_t *) lp; 691 692 if (entp->delete_flag) continue; 693 694 if (epdb_is_replace_candidate(entp, object, tfp, addr) && 695 entp->interface.vers_minor > tfp->interface.vers_minor) 696 { 697 assert(status != NULL); 698 SET_STATUS(status, ept_s_invalid_entry); 699 goto DONE; 700 } 701 } 702 703 /* 704 * Scan the list again and delete all replace candidates that have 705 * network address that matches the network entry of the new entry. 706 */ 707 for (lp = lp_first; lp != NULL; lp = lp_next) 708 { 709 db_entry_t *entp = (db_entry_t *) lp; 710 711 /* 712 * Point to next entry - may remove this one from the list 713 * and delete it 714 */ 715 lp_next = db_list_next(list_type, lp); 716 717 if (entp->delete_flag) continue; 718 719 if (epdb_is_replace_candidate(entp, object, tfp, addr)) 720 { 721 rpc__naf_addr_inq_netaddr(entp->addr, &netaddr2, &tmp_st); 722 if (! STATUS_OK(&tmp_st)) continue; 723 724 if (strcmp((char *) netaddr, (char *) netaddr2) == 0) 725 { 726 /* Entry matches target in all fields except 727 * endpoint so delete it 728 */ 729 epdb_delete_entry(h, entp, &tmp_st); 730 } 731 732 rpc_string_free(&netaddr2, &tmp_st); 733 } 734 } 735 736 assert(status != NULL); 737 SET_STATUS_OK(status); 738 739DONE: 740 741 rpc_string_free(&netaddr, &tmp_st); 742 743} 744 745/* 746 * epdb_delete_entries_by_obj_if_addr 747 * 748 * Delete entries which match target object (if speced), interface, and addr 749 */ 750INTERNAL void epdb_delete_entries_by_obj_if_addr(h, object_speced, object, interface, addr, status) 751struct db *h; 752boolean32 object_speced; 753uuid_p_t object; 754rpc_if_id_p_t interface; 755rpc_addr_p_t addr; 756error_status_t *status; 757{ 758 unsigned32 ndelete; 759 db_lists_t *lp, 760 *lp_next; 761 db_entry_t *entp; 762 error_status_t tmp_st; 763 764 ndelete = 0; 765 766 for (lp = db_list_first(&h->lists_mgmt, db_c_interface_list, &interface->uuid); 767 lp != NULL; lp = lp_next) 768 { 769 /* 770 * Point to next entry - may remove this one from the list 771 * and delete it 772 */ 773 lp_next = db_list_next(db_c_interface_list, lp); 774 775 entp = (db_entry_t *) lp; 776 777 if (entp->delete_flag) continue; 778 779 if (((! object_speced) || uuid_equal(object, &entp->object, &tmp_st)) && 780 (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st)) && 781 (interface->vers_major == entp->interface.vers_major) && 782 (interface->vers_minor == entp->interface.vers_minor) && 783 (rpc__naf_addr_compare(addr, entp->addr, &tmp_st))) 784 { 785 /* Entry matches target object (if speced), 786 * interface, and addr so delete it 787 */ 788 epdb_delete_entry(h, entp, status); 789 if (! STATUS_OK(status)) return; 790 791 ndelete++; 792 } 793 } 794 795 assert(status != NULL); 796 if (ndelete > 0) 797 SET_STATUS_OK(status); 798 else 799 SET_STATUS(status, ept_s_not_registered); 800} 801 802/* epdb_lookup_entry 803 * Return pointer to entry which exactly matches 804 * xentry 805 * Return all entries, even ones marked as deleted 806 */ 807INTERNAL db_entry_t *epdb_lookup_entry(h, xentry) 808struct db *h; 809ept_entry_p_t xentry; 810{ 811 db_entry_t *entp; 812 db_lists_t *lp; 813 db_list_type_t list_type; 814 rpc_if_id_t interface; 815 error_status_t tmp_st; 816 817 if (! uuid_is_nil(&xentry->object, &tmp_st)) 818 { 819 list_type = db_c_object_list; 820 lp = db_list_first(&h->lists_mgmt, db_c_object_list, &xentry->object); 821 } 822 else 823 { 824 tower_to_if_id(xentry->tower, &interface, &tmp_st); 825 list_type = db_c_interface_list; 826 lp = db_list_first(&h->lists_mgmt, db_c_interface_list, &interface.uuid); 827 } 828 829 for ( ; lp != NULL; lp = db_list_next(list_type, lp)) 830 { 831 entp = (db_entry_t *) lp; 832 833 if (uuid_equal(&xentry->object, &entp->object, &tmp_st) && 834 (xentry->tower->tower_length == entp->tower.tower_length) && 835 (memcmp((char *) xentry->tower->tower_octet_string, 836 (char *) entp->tower.tower_octet_string, 837 xentry->tower->tower_length) == 0)) 838 { 839 return(entp); 840 } 841 } 842 843 return(NULL); 844} 845 846 847/* 848 * Add a new entry to the database. If the entry already exists simply 849 * modify its annotation field (it's the only field that might be 850 * different), clear some of its mgmt fields and update the entry 851 * on disk. 852 * 853 * Note: All tower floors in an entry must be valid and non-nil 854 * (eg. nil interface uuid is prohibited). 855 */ 856PRIVATE void epdb_insert(h_, xentry, replace, status) 857epdb_handle_t h_; 858ept_entry_p_t xentry; 859boolean32 replace; 860error_status_t *status; 861{ 862 struct db *h = (struct db *) h_; 863 db_entry_t *entp; 864 twr_fields_t twr_fields; 865 rpc_addr_p_t addr; 866 error_status_t tmp_st; 867 868 addr = NULL; 869 870 /* Parse the new entry's tower and check 871 * whether the new entry is ok. 872 * Prefill status to bad entry for quick return. 873 */ 874 SET_STATUS(status, ept_s_invalid_entry); 875 876 /* 877 * Parse xentry's tower into twr_fields 878 */ 879 tower_to_fields(xentry->tower, &twr_fields, &tmp_st); 880 if (!STATUS_OK(&tmp_st)) return; 881 882 tower_to_addr(xentry->tower, &addr, &tmp_st); 883 if (!STATUS_OK(&tmp_st)) return; 884 885 epdb_chk_entry(xentry, &twr_fields, addr, &tmp_st); 886 if (!STATUS_OK(&tmp_st)) 887 { 888 if (addr != NULL) rpc__naf_addr_free(&addr, &tmp_st); 889 return; 890 } 891 892 db_lock(h); 893 894 if (replace) 895 { 896 /* Delete entries that match 897 * in all fields except endpoint 898 */ 899 epdb_delete_replaceable_entries(h, &xentry->object, &twr_fields, addr, status); 900 if (! STATUS_OK(status)) 901 { 902 rpc__naf_addr_free(&addr, &tmp_st); 903 db_unlock(h); 904 return; 905 } 906 } 907 908 entp = epdb_lookup_entry(h, xentry); 909 910 if (entp == NULL) 911 { 912 /* New entry 913 * insert it in dbase and add it to lists 914 */ 915 epdb_insert_entry(h, xentry, &twr_fields, addr, &entp, status); 916 } 917 else 918 { 919 /* Existing entry - just replace annotation and clear some mgmt fields 920 * Free unused addr (already have it for this entry) 921 */ 922 rpc__naf_addr_free(&addr, &tmp_st); 923 924 epdb_replace_entry(h, xentry, entp, status); 925 } 926 927 db_unlock(h); 928 929 if (! STATUS_OK(status)) 930 { 931 if (addr != NULL) rpc__naf_addr_free(&addr, &tmp_st); 932 db_to_ept_ecode(status); 933 } 934} 935 936/* 937 * Remove an entry from the database. 938 * Only a database entry which exactly matches 939 * xentry is deleted. 940 */ 941PRIVATE void epdb_delete(h_, xentry, status) 942epdb_handle_t h_; 943ept_entry_p_t xentry; 944error_status_t *status; 945{ 946 struct db *h = (struct db *) h_; 947 db_entry_t *entp; 948 949 SET_STATUS_OK(status); 950 951 db_lock(h); 952 953 entp = epdb_lookup_entry(h, xentry); 954 955 if (entp != NULL) 956 { 957 if (entp->delete_flag) 958 SET_STATUS(status, ept_s_not_registered); 959 else 960 { 961 /* 962 * Matching entry found so delete it 963 */ 964 epdb_delete_entry(h, entp, status); 965 if (! STATUS_OK(status)) db_to_ept_ecode(status); 966 } 967 } 968 else 969 SET_STATUS(status, ept_s_not_registered); 970 971 db_unlock(h); 972} 973 974PRIVATE void epdb_mgmt_delete(h_, object_speced, object, tower, status) 975epdb_handle_t h_; 976boolean32 object_speced; 977uuid_p_t object; 978twr_p_t tower; 979error_status_t *status; 980{ 981 struct db *h = (struct db *) h_; 982 rpc_if_id_t interface; 983 rpc_addr_p_t addr; 984 error_status_t tmp_st; 985 986 SET_STATUS(status, ept_s_invalid_entry); 987 988 tower_to_if_id(tower, &interface, status); 989 if (! STATUS_OK(status)) return; 990 tower_to_addr(tower, &addr, status); 991 if (! STATUS_OK(status)) return; 992 993 db_lock(h); 994 995 epdb_delete_entries_by_obj_if_addr(h, object_speced, object, &interface, addr, status); 996 if (! STATUS_OK(status)) db_to_ept_ecode(status); 997 998 db_unlock(h); 999 1000 rpc__naf_addr_free(&addr, &tmp_st); 1001} 1002 1003 1004/* 1005 * epdb_lookup 1006 * Return entries that match filter speced by inquiry_type, vers_option, 1007 * object, and interface. 1008 * 1009 */ 1010PRIVATE void epdb_lookup(h_, inquiry_type, object, interface, vers_option, entry_handle, max_ents, 1011 num_ents, entries, status) 1012epdb_handle_t h_; 1013unsigned32 inquiry_type; 1014uuid_p_t object; 1015rpc_if_id_p_t interface; 1016unsigned32 vers_option; 1017ept_lookup_handle_t *entry_handle; 1018unsigned32 max_ents; 1019unsigned32 *num_ents; 1020ept_entry_t entries[]; 1021error_status_t *status; 1022{ 1023 struct db *h = (struct db *) h_; 1024 1025 *num_ents = 0; 1026 1027 /* lock database before delete_context or lookup 1028 */ 1029 db_lock(h); 1030 1031 if (entries == NULL) 1032 { 1033 db_delete_context(h, entry_handle); 1034 SET_STATUS(status, ept_s_invalid_entry); 1035 db_unlock(h); 1036 return; 1037 } 1038 1039 lookup(h, inquiry_type, object, interface, vers_option, entry_handle, max_ents, num_ents, entries, status); 1040 1041 db_unlock(h); 1042} 1043 1044INTERNAL void lookup(h, inquiry_type, object, interface, vers_option, entry_handle, max_ents, 1045 num_ents, entries, status) 1046struct db *h; 1047unsigned32 inquiry_type; 1048uuid_p_t object; 1049rpc_if_id_p_t interface; 1050unsigned32 vers_option; 1051ept_lookup_handle_t *entry_handle; 1052unsigned32 max_ents; 1053unsigned32 *num_ents; 1054ept_entry_t entries[]; 1055error_status_t *status; 1056{ 1057 unsigned32 pass; 1058 db_list_type_t list_type; 1059 db_lists_t *lp; 1060 unsigned32 i; 1061 1062 SET_STATUS_OK(status); 1063 1064 if ((entry_handle == NULL) || (*entry_handle == NULL)) 1065 { 1066 /* no context saved so init context 1067 */ 1068 switch ((int)inquiry_type) 1069 { 1070 case rpc_c_ep_all_elts: 1071 pass = 1; 1072 list_type = db_c_entry_list; 1073 lp = db_list_first(&h->lists_mgmt, list_type, NULL); 1074 break; 1075 1076 case rpc_c_ep_match_by_if: 1077 case rpc_c_ep_match_by_both: 1078 pass = 1; 1079 list_type = db_c_interface_list; 1080 lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid); 1081 break; 1082 1083 case rpc_c_ep_match_by_obj: 1084 pass = 1; 1085 list_type = db_c_object_list; 1086 lp = db_list_first(&h->lists_mgmt, list_type, object); 1087 break; 1088 1089 default: 1090 *status = rpc_s_invalid_inquiry_type; 1091 return; 1092 } 1093 } 1094 else 1095 { 1096 /* context has been saved. 1097 * restore context 1098 */ 1099 db_get_context(h, entry_handle, &list_type, &lp, &pass, status); 1100 if (! STATUS_OK(status)) 1101 { 1102 *entry_handle = NULL; 1103 return; 1104 } 1105 1106 /* do some sanity checking on inquiry_type/context info 1107 */ 1108 switch ((int)inquiry_type) 1109 { 1110 case rpc_c_ep_all_elts: 1111 if (list_type != db_c_entry_list) 1112 *status = ept_s_invalid_context; 1113 break; 1114 1115 case rpc_c_ep_match_by_if: 1116 case rpc_c_ep_match_by_both: 1117 if (list_type != db_c_interface_list) 1118 *status = ept_s_invalid_context; 1119 break; 1120 1121 case rpc_c_ep_match_by_obj: 1122 if (list_type != db_c_object_list) 1123 *status = ept_s_invalid_context; 1124 break; 1125 1126 default: 1127 *status = rpc_s_invalid_inquiry_type; 1128 break; 1129 } 1130 1131 if (! STATUS_OK(status)) 1132 { 1133 db_delete_context(h, entry_handle); 1134 return; 1135 } 1136 } 1137 1138 lookup_match(inquiry_type, object, interface, vers_option, max_ents, num_ents, entries, list_type, 1139 &lp, status); 1140 1141 if (! STATUS_OK(status)) 1142 { 1143 /* Lookup failed so delete 1144 * the context handle and free 1145 * the towers that have been allocated 1146 */ 1147 db_delete_context(h, entry_handle); 1148 1149 for (i = 0; i < *num_ents; i++) 1150 rpc_ss_free(entries[i].tower); 1151 1152 *num_ents = 0; 1153 return; 1154 } 1155 1156 db_save_context(h, entry_handle, list_type, lp, pass); 1157 1158 if (*num_ents == 0) 1159 { 1160 SET_STATUS(status, ept_s_not_registered); 1161 } 1162} 1163 1164INTERNAL void lookup_match(inquiry_type, object, interface, vers_option, max_ents, num_ents, entries, list_type, 1165 lpp, status) 1166unsigned32 inquiry_type; 1167uuid_p_t object; 1168rpc_if_id_p_t interface; 1169unsigned32 vers_option; 1170unsigned32 max_ents; 1171unsigned32 *num_ents; 1172ept_entry_t entries[]; 1173unsigned32 list_type; 1174db_lists_t **lpp; 1175error_status_t *status; 1176{ 1177 boolean32 match; 1178 db_lists_t *lp; 1179 db_entry_t *entp; 1180 error_status_t tmp_st; 1181 1182 for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp)) 1183 { 1184 entp = (db_entry_t *) lp; 1185 1186 if (entp->delete_flag) continue; 1187 1188 match = false; 1189 switch ((int)inquiry_type) 1190 { 1191 case rpc_c_ep_all_elts: 1192 match = true; 1193 break; 1194 1195 case rpc_c_ep_match_by_if: 1196 if (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st)) 1197 match = true; 1198 break; 1199 1200 case rpc_c_ep_match_by_obj: 1201 if (uuid_equal(object, &entp->object, &tmp_st)) 1202 match = true; 1203 break; 1204 1205 case rpc_c_ep_match_by_both: 1206 if (uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st) && 1207 uuid_equal(object, &entp->object, &tmp_st)) 1208 match = true; 1209 break; 1210 1211 default: 1212 assert(status != NULL); 1213 *status = rpc_s_invalid_inquiry_type; 1214 return; 1215 1216 } 1217 1218 if (match) 1219 { 1220 if ((inquiry_type == rpc_c_ep_match_by_if) || (inquiry_type == rpc_c_ep_match_by_both)) 1221 { 1222 /* check interface version 1223 */ 1224 1225 match = false; 1226 switch ((int)vers_option) 1227 { 1228 case rpc_c_vers_all: 1229 match = true; 1230 break; 1231 1232 case rpc_c_vers_compatible: 1233 if ((interface->vers_major == entp->interface.vers_major) && 1234 (interface->vers_minor <= entp->interface.vers_minor)) 1235 match = true; 1236 break; 1237 1238 case rpc_c_vers_exact: 1239 if ((interface->vers_major == entp->interface.vers_major) && 1240 (interface->vers_minor == entp->interface.vers_minor)) 1241 match = true; 1242 break; 1243 1244 case rpc_c_vers_major_only: 1245 if (interface->vers_major == entp->interface.vers_major) 1246 match = true; 1247 break; 1248 1249 case rpc_c_vers_upto: 1250 if (interface->vers_major > entp->interface.vers_major) 1251 match = true; 1252 else 1253 if ((interface->vers_major == entp->interface.vers_major) && 1254 (interface->vers_minor >= entp->interface.vers_minor)) 1255 match = true; 1256 break; 1257 1258 default: 1259 assert(status != NULL); 1260 *status = rpc_s_invalid_vers_option; 1261 return; 1262 } 1263 } 1264 } 1265 1266 if (match) 1267 { 1268 if (*num_ents >= max_ents) 1269 { 1270 break; 1271 } 1272 1273 epdb_to_ept(entp, &entries[*num_ents], status); 1274 if (! STATUS_OK(status)) return; 1275 1276 (*num_ents)++; 1277 } 1278 } 1279 1280 *lpp = lp; 1281 1282 SET_STATUS_OK(status); 1283} 1284 1285/* 1286 * epdb_fwd 1287 * 1288 * Invoke map or map_mgmt to do a sequence of searches through the 1289 * endpoint map for appropriate entries to forward to and return pointers 1290 * to these entries. Copy the entries' addr info into fwd_addrs. 1291 * 1292 * map_mgmt is used for the search if the interface is the mgmt interface, 1293 * otherwise map is used. 1294 * 1295 * If bad status is returned delete the search context, otherwise map 1296 * will save it. 1297 * 1298 * NB: caller should set *num_ents to 0 or appropriate offset into fwd_addrs. 1299 * 1300 * Note: we do not forward to an entry with a nil interface id 1301 * AND a nil object id. If this ever becomes desireable, it will 1302 * likely require visiting (fixing) the protocol service implementations 1303 * that use DG style forwarding. The implementations may try to forward 1304 * first through the map and only if the forward map fails, then attempt 1305 * to perform normal pkt handling. The problem is that allowing a tuple 1306 * with a nil interface AND object id to be registered will result in 1307 * an inexact lookup match (due to the nil interface id) for operations 1308 * that are really for the server implementing the endpoint map operations. 1309 * 1310 * Also note that rpcd.c/fwd_map invokes epdb_fwd with max_ents = 1 and 1311 * map_handle = NULL. We could remove the context handle mgmt code from 1312 * epdb_fwd and gain some in performance - but we'd still need to leave 1313 * the context handle code in map and map_match for epdb_map. 1314 */ 1315 1316PRIVATE void epdb_fwd(h_, object, interface, data_rep, 1317 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, 1318 addr, map_handle, max_ents, num_ents, fwd_addrs, status) 1319epdb_handle_t h_; 1320uuid_p_t object; 1321rpc_if_id_p_t interface; 1322rpc_syntax_id_p_t data_rep; 1323rpc_protocol_id_t rpc_protocol; 1324unsigned32 rpc_protocol_vers_major; 1325unsigned32 rpc_protocol_vers_minor; 1326rpc_addr_p_t addr; 1327ept_lookup_handle_t *map_handle; 1328unsigned32 max_ents; 1329unsigned32 *num_ents; 1330rpc_addr_p_t fwd_addrs[]; 1331unsigned32 *status; 1332{ 1333 struct db *h = (struct db *) h_; 1334 rpc_if_rep_p_t mgmt_if_rep; 1335 db_entry_t **db_entries; 1336 unsigned32 start_ent; 1337 unsigned32 i; 1338 error_status_t tmp_st; 1339 1340 mgmt_if_rep = (rpc_if_rep_p_t) mgmt_v1_0_s_ifspec; 1341 1342 if (db_different_context(h, map_handle, status)) 1343 return; 1344 1345 db_entries = (db_entry_t **) malloc(max_ents * sizeof(db_entry_p_t)); 1346 1347 /* lock database before delete_context or lookup 1348 */ 1349 db_lock(h); 1350 1351 if ((fwd_addrs == NULL) || (db_entries == NULL) || (max_ents == 0) || (*num_ents > max_ents)) 1352 { 1353 if (db_entries != NULL) free(db_entries); 1354 db_delete_context(h, map_handle); 1355 SET_STATUS(status, ept_s_cant_perform_op); 1356 db_unlock(h); 1357 return; 1358 } 1359 1360 start_ent = *num_ents; 1361 1362 if (uuid_equal(&interface->uuid, &mgmt_if_rep->id, &tmp_st)) 1363 map_mgmt(h, object, data_rep, 1364 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr->rpc_protseq_id, 1365 map_handle, max_ents, num_ents, db_entries, status); 1366 else 1367 map(h, object, interface, data_rep, 1368 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, addr->rpc_protseq_id, 1369 map_handle, max_ents, num_ents, db_entries, status); 1370 if (! STATUS_OK(status)) 1371 { 1372 free(db_entries); 1373 db_unlock(h); 1374 return; 1375 } 1376 1377 for (i = start_ent; i < *num_ents; i++) 1378 { 1379 rpc__naf_addr_copy(db_entries[i]->addr, &fwd_addrs[i], status); 1380 if (! STATUS_OK(status)) 1381 { 1382 /* don't remember context but return 1383 * addrs that already copied to oput array. 1384 */ 1385 db_delete_context(h, map_handle); 1386 *num_ents = i; 1387 if (*num_ents > 0) 1388 { 1389 SET_STATUS_OK(status); 1390 } 1391 else 1392 { 1393 SET_STATUS(status, ept_s_cant_perform_op); 1394 } 1395 break; 1396 } 1397 } 1398 1399 free(db_entries); 1400 1401 db_unlock(h); 1402} 1403 1404/* epdb_map 1405 * Invoke map or map_mgmt to do a sequence of searches through the 1406 * endpoint map for appropriate entries to forward to and return pointers 1407 * to these entries. Copy the entries' tower info into fwd_towers. 1408 * 1409 * map_mgmt is used for the search if the interface is the mgmt interface, 1410 * otherwise map is used. 1411 * 1412 * If bad status is returned delete the search context, otherwise map 1413 * will save it. 1414 * 1415 * NB: caller should set *num_ents to 0 or appropriate offset into fwd_towers. 1416 */ 1417PRIVATE void epdb_map(h_, object, map_tower, map_handle, max_ents, num_ents, fwd_towers, status) 1418epdb_handle_t h_; 1419uuid_p_t object; 1420twr_p_t map_tower; 1421ept_lookup_handle_t *map_handle; 1422unsigned32 max_ents; 1423unsigned32 *num_ents; 1424twr_t *fwd_towers[]; 1425unsigned32 *status; 1426{ 1427 struct db *h = (struct db *) h_; 1428 twr_fields_t twr_fields, *tfp; 1429 rpc_if_rep_p_t mgmt_if_rep; 1430 db_entry_t **db_entries; 1431 unsigned32 start_ent; 1432 unsigned32 i; 1433 error_status_t tmp_st; 1434 1435 tfp = &twr_fields; 1436 mgmt_if_rep = (rpc_if_rep_p_t) mgmt_v1_0_s_ifspec; 1437 1438 if (db_different_context(h, map_handle, status)) 1439 return; 1440 1441 /* lock database before delete_context or map 1442 */ 1443 db_lock(h); 1444 1445 tower_to_fields(map_tower, &twr_fields, status); 1446 if (! STATUS_OK(status)) 1447 { 1448 db_delete_context(h, map_handle); 1449 SET_STATUS(status, ept_s_invalid_entry); 1450 db_unlock(h); 1451 return; 1452 } 1453 1454 epdb_chk_map_entry(&twr_fields, status); 1455 if (! STATUS_OK(status)) 1456 { 1457 db_delete_context(h, map_handle); 1458 SET_STATUS(status, ept_s_invalid_entry); 1459 db_unlock(h); 1460 return; 1461 } 1462 1463 db_entries = (db_entry_t **) malloc(max_ents * sizeof(db_entry_p_t)); 1464 1465 if ((db_entries == NULL) || (fwd_towers == NULL) || (max_ents == 0) || (*num_ents > max_ents)) 1466 { 1467 if (db_entries != NULL) free(db_entries); 1468 db_delete_context(h, map_handle); 1469 assert(status != NULL); 1470 SET_STATUS(status, ept_s_cant_perform_op); 1471 db_unlock(h); 1472 return; 1473 } 1474 1475 start_ent = *num_ents; 1476 1477 if (uuid_equal(&tfp->interface.uuid, &mgmt_if_rep->id, &tmp_st)) 1478 map_mgmt(h, object, &tfp->data_rep, 1479 tfp->rpc_protocol, tfp->rpc_protocol_vers_major, tfp->rpc_protocol_vers_minor, 1480 tfp->protseq, map_handle, max_ents, num_ents, db_entries, status); 1481 else 1482 map(h, object, &tfp->interface, &tfp->data_rep, 1483 tfp->rpc_protocol, tfp->rpc_protocol_vers_major, tfp->rpc_protocol_vers_minor, 1484 tfp->protseq, map_handle, max_ents, num_ents, db_entries, status); 1485 if (! STATUS_OK(status)) 1486 { 1487 free(db_entries); 1488 db_unlock(h); 1489 return; 1490 } 1491 1492 for (i = start_ent; i < *num_ents; i++) 1493 { 1494 tower_ss_copy(&(db_entries[i]->tower), &fwd_towers[i], status); 1495 if (! STATUS_OK(status)) 1496 { 1497 /* don't remember context but return 1498 * towers that already copied to oput array. 1499 */ 1500 db_delete_context(h, map_handle); 1501 *num_ents = i; 1502 if (*num_ents > 0) 1503 { 1504 SET_STATUS_OK(status); 1505 } 1506 else 1507 { 1508 SET_STATUS(status, ept_s_cant_perform_op); 1509 } 1510 break; 1511 } 1512 } 1513 1514 free(db_entries); 1515 1516 db_unlock(h); 1517} 1518 1519/* 1520 * Search the endpoint database looking for entries which match the target object, 1521 * interface, etc. 1522 * 1523 * If the target object is non-nil, do a 2 pass search 1524 * First, search the objectq looking for exact object/interface matches. 1525 * Second, search the interfaceq for interface match/object nil 1526 * 1527 * If the target object is nil 1528 * Search the interfaceq for interface match/object nil (same as pass 2 above) 1529 * 1530 * The following table gives some examples of applying the above algorithm 1531 * to various map entrys (the table assumes that the entrys already exactly 1532 * match the data rep, protseq, versions, etc. specified in the key): 1533 * 1534 * Keys and entrys of the form: <object,interface> 1535 * Matches (in order of specificity): 1536 * Moi - Match on Object and Interface 1537 * Mi - Match on Interface 1538 * No Match: ' - ' 1539 * 1540 * 1541 * \ Map | 1542 * \ entry | 1543 * key \ | <nil,I1> <nil,I2> <O1,I1> <O1,I2> <O2,I1> 1544 * -----------|------------------------------------------- 1545 * <nil,I1> | Moi - - - - 1546 * <O1,I1> | Mi - Moi - - 1547 * 1548 */ 1549 1550INTERNAL void map(h, object, interface, data_rep, 1551 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1552 map_handle, max_ents, n_ents, db_entries, status) 1553struct db *h; 1554uuid_p_t object; 1555rpc_if_id_p_t interface; 1556rpc_syntax_id_p_t data_rep; 1557rpc_protocol_id_t rpc_protocol; 1558unsigned32 rpc_protocol_vers_major; 1559unsigned32 rpc_protocol_vers_minor; 1560rpc_protseq_id_t protseq; 1561ept_lookup_handle_t *map_handle; 1562unsigned32 max_ents; 1563unsigned32 *n_ents; 1564db_entry_t *db_entries[]; 1565unsigned32 *status; 1566{ 1567 unsigned32 pass; 1568 db_list_type_t list_type; 1569 db_lists_t *lp; 1570 error_status_t tmp_st; 1571 1572 SET_STATUS_OK(status); 1573 1574 if ((map_handle == NULL) || (*map_handle == NULL)) 1575 { 1576 if (uuid_is_nil(object, &tmp_st)) 1577 { 1578 pass = 2; 1579 list_type = db_c_interface_list; 1580 lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid); 1581 } 1582 else 1583 { 1584 pass = 1; 1585 list_type = db_c_object_list; 1586 lp = db_list_first(&h->lists_mgmt, list_type, object); 1587 } 1588 } 1589 else 1590 { 1591 db_get_context(h, map_handle, &list_type, &lp, &pass, status); 1592 if (! STATUS_OK(status)) return; 1593 } 1594 1595 /* search objectq for object/interface match */ 1596 if (pass == 1) 1597 { 1598 map_match( 1599 object, interface, data_rep, 1600 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1601 max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status); 1602 if (! STATUS_OK(status)) 1603 { 1604 db_delete_context(h, map_handle); 1605 return; 1606 } 1607 1608 if ((*n_ents >= max_ents) && ((lp != NULL) || (map_handle == NULL))) 1609 { 1610 /* If entry buffer is full and 1611 * have found next match or are not saving context 1612 * save context and return 1613 * (save_context just returns if map_handle == NULL) 1614 */ 1615 db_save_context(h, map_handle, list_type, lp, pass); 1616 return; 1617 } 1618 1619 /* get organized for next pass 1620 */ 1621 pass = 2; 1622 list_type = db_c_interface_list; 1623 lp = db_list_first(&h->lists_mgmt, list_type, &interface->uuid); 1624 1625 } /* end of pass 1 */ 1626 1627 /* search interfaceq for interface match/object nil */ 1628 if (pass == 2) 1629 { 1630 map_match( 1631 &nil_uuid, interface, data_rep, 1632 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1633 max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status); 1634 if (! STATUS_OK(status)) 1635 { 1636 db_delete_context(h, map_handle); 1637 return; 1638 } 1639 } 1640 1641 /* If there's context to be saved, save it. 1642 * If there's no context to save, free entry_handle's 1643 * context and set entry_handle to NULL 1644 */ 1645 db_save_context(h, map_handle, list_type, lp, pass); 1646 1647 if (*n_ents == 0) 1648 { 1649 SET_STATUS(status, ept_s_not_registered); 1650 } 1651} 1652 1653INTERNAL void map_match( 1654 object, interface, data_rep, 1655 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1656 max_ents, n_ents, entries, map_handle, pass, list_type, lpp, status) 1657uuid_p_t object; 1658rpc_if_id_p_t interface; 1659rpc_syntax_id_p_t data_rep; 1660rpc_protocol_id_t rpc_protocol; 1661unsigned32 rpc_protocol_vers_major; 1662unsigned32 rpc_protocol_vers_minor ATTRIBUTE_UNUSED; 1663rpc_protseq_id_t protseq; 1664unsigned32 max_ents; 1665unsigned32 *n_ents; 1666db_entry_t *entries[]; 1667ept_lookup_handle_t *map_handle; 1668unsigned32 pass ATTRIBUTE_UNUSED; 1669db_list_type_t list_type; 1670db_lists_t **lpp; 1671unsigned32 *status; 1672{ 1673 boolean32 object_nil; 1674 unsigned32 data_rep_vers_major, 1675 data_rep_vers_minor; 1676 unsigned32 tmp_st; 1677 db_lists_t *lp; 1678 db_entry_t *entp; 1679 1680 SET_STATUS_OK(status); 1681 1682 object_nil = uuid_is_nil(object, &tmp_st); 1683 data_rep_vers_major = RPC_IF_VERS_MAJOR(data_rep->version); 1684 data_rep_vers_minor = RPC_IF_VERS_MINOR(data_rep->version); 1685 1686 for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp)) 1687 { 1688 entp = (db_entry_t *) lp; 1689 1690 if (entp->delete_flag) continue; 1691 1692 if (((object_nil && entp->object_nil) || 1693 uuid_equal(object, &entp->object, &tmp_st)) && 1694 uuid_equal(&interface->uuid, &entp->interface.uuid, &tmp_st) && 1695 (interface->vers_major == entp->interface.vers_major) && 1696 (interface->vers_minor <= entp->interface.vers_minor) && 1697 (protseq == entp->addr->rpc_protseq_id) && 1698 uuid_equal(&data_rep->id, &entp->data_rep_id, &tmp_st) && 1699 (data_rep_vers_major == entp->data_rep_vers_major) && 1700 (data_rep_vers_minor <= entp->data_rep_vers_minor) && 1701 (rpc_protocol == entp->rpc_protocol) && 1702 (rpc_protocol_vers_major == entp->rpc_protocol_vers_major)) 1703 /* 1704 * We dont do this so we can rev the minor protocol number 1705 * && (rpc_protocol_vers_minor <= entp->rpc_protocol_vers_minor) ) 1706 */ 1707 { 1708 /* 1709 * found the next match and have filled the 1710 * entries vector so quit search 1711 */ 1712 if (*n_ents >= max_ents) 1713 { 1714 *lpp = lp; 1715 return; 1716 } 1717 1718 entries[*n_ents] = entp; 1719 1720 (*n_ents)++; 1721 1722 /* if not saving search context don't look for next matching 1723 * entry 1724 */ 1725 if ((map_handle == NULL) && (*n_ents >= max_ents)) 1726 { 1727 *lpp = lp; 1728 return; 1729 } 1730 } /* entry == target */ 1731 1732 } /* for lp */ 1733 1734 *lpp = lp; 1735} 1736 1737/* map_mgmt 1738 * Packet is for the mgmt interface which all processes export. 1739 * Look for entries with matching object, protseq, data_rep, 1740 * and rpc_protocol. Only return one entry per endpoint. 1741 */ 1742INTERNAL void map_mgmt(h, object, data_rep, 1743 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1744 map_handle, max_ents, n_ents, db_entries, status) 1745struct db *h; 1746uuid_p_t object; 1747rpc_syntax_id_p_t data_rep; 1748rpc_protocol_id_t rpc_protocol; 1749unsigned32 rpc_protocol_vers_major; 1750unsigned32 rpc_protocol_vers_minor; 1751rpc_protseq_id_t protseq; 1752ept_lookup_handle_t *map_handle; 1753unsigned32 max_ents; 1754unsigned32 *n_ents; 1755db_entry_t *db_entries[]; 1756unsigned32 *status; 1757{ 1758 unsigned32 pass; 1759 db_list_type_t list_type; 1760 db_lists_t *lp; 1761 error_status_t tmp_st; 1762 1763 if (uuid_is_nil(object, &tmp_st)) 1764 { 1765 db_delete_context(h, map_handle); 1766 SET_STATUS(status, ept_s_invalid_entry); 1767 return; 1768 } 1769 1770 if ((map_handle == NULL) || (*map_handle == NULL)) 1771 { 1772 pass = 1; 1773 list_type = db_c_object_list; 1774 lp = db_list_first(&h->lists_mgmt, list_type, object); 1775 } 1776 else 1777 { 1778 db_get_context(h, map_handle, &list_type, &lp, &pass, status); 1779 if (! STATUS_OK(status)) return; 1780 } 1781 1782 map_mgmt_match( 1783 object, data_rep, 1784 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1785 max_ents, n_ents, db_entries, map_handle, pass, list_type, &lp, status); 1786 if (! STATUS_OK(status)) 1787 { 1788 db_delete_context(h, map_handle); 1789 return; 1790 } 1791 1792 /* If there's context to be saved, save it. 1793 * If there's no context to save, free map_handle's 1794 * context and set map_handle to NULL 1795 */ 1796 db_save_context(h, map_handle, list_type, lp, pass); 1797 1798 if (*n_ents == 0) 1799 { 1800 assert(status != NULL); 1801 SET_STATUS(status, ept_s_not_registered); 1802 } 1803} 1804 1805INTERNAL void map_mgmt_match( 1806 object, data_rep, 1807 rpc_protocol, rpc_protocol_vers_major, rpc_protocol_vers_minor, protseq, 1808 max_ents, n_ents, entries, map_handle, pass, list_type, lpp, status) 1809uuid_p_t object; 1810rpc_syntax_id_p_t data_rep; 1811rpc_protocol_id_t rpc_protocol; 1812unsigned32 rpc_protocol_vers_major; 1813unsigned32 rpc_protocol_vers_minor ATTRIBUTE_UNUSED; 1814rpc_protseq_id_t protseq; 1815unsigned32 max_ents; 1816unsigned32 *n_ents; 1817db_entry_t *entries[]; 1818ept_lookup_handle_t *map_handle; 1819unsigned32 pass ATTRIBUTE_UNUSED; 1820db_list_type_t list_type; 1821db_lists_t **lpp; 1822unsigned32 *status; 1823{ 1824 unsigned32 data_rep_vers_major, 1825 data_rep_vers_minor; 1826 unsigned32 tmp_st; 1827 db_lists_t *lp; 1828 db_entry_t *entp; 1829 1830 SET_STATUS_OK(status); 1831 1832 data_rep_vers_major = RPC_IF_VERS_MAJOR(data_rep->version); 1833 data_rep_vers_minor = RPC_IF_VERS_MINOR(data_rep->version); 1834 1835 for (lp = *lpp; lp != NULL; lp = db_list_next(list_type, lp)) 1836 { 1837 entp = (db_entry_t *) lp; 1838 1839 if (entp->delete_flag) continue; 1840 1841 if (uuid_equal(object, &entp->object, &tmp_st) && 1842 (protseq == entp->addr->rpc_protseq_id) && 1843 uuid_equal(&data_rep->id, &entp->data_rep_id, &tmp_st) && 1844 (data_rep_vers_major == entp->data_rep_vers_major) && 1845 (data_rep_vers_minor <= entp->data_rep_vers_minor) && 1846 (rpc_protocol == entp->rpc_protocol) && 1847 (rpc_protocol_vers_major == entp->rpc_protocol_vers_major) && 1848 /* 1849 * We dont do this so we can rev the minor protocol number 1850 * (rpc_protocol_vers_minor <= entp->rpc_protocol_vers_minor) && 1851 */ 1852 /* match - see whether already returning 1853 * this endpoint in entries 1854 */ 1855 map_mgmt_endpt_unique(entp->addr, *n_ents, entries) ) 1856 { 1857 /* 1858 * found the next match with unique endpoint 1859 */ 1860 1861 /* 1862 * have filled the entries vector so quit search 1863 */ 1864 if (*n_ents >= max_ents) 1865 { 1866 *lpp = lp; 1867 return; 1868 } 1869 1870 entries[*n_ents] = entp; 1871 1872 (*n_ents)++; 1873 1874 /* if not saving search context don't look for next matching 1875 * entry 1876 */ 1877 if ((map_handle == NULL) && (*n_ents >= max_ents)) 1878 { 1879 *lpp = lp; 1880 return; 1881 } 1882 } /* entry == target */ 1883 1884 } /* for lp */ 1885 1886 *lpp = lp; 1887} 1888 1889/* map_mgmt_endpt_unique 1890 * return true if addr does not match addr of any entry in entries 1891 * otherwise return false 1892 */ 1893INTERNAL boolean32 map_mgmt_endpt_unique(addr, n_ents, entries) 1894rpc_addr_p_t addr; 1895unsigned32 n_ents; 1896db_entry_t *entries[]; 1897{ 1898 unsigned32 i; 1899 error_status_t tmp_st; 1900 1901 for (i = 0; i < n_ents; i++) 1902 { 1903 /* matching endpoint 1904 */ 1905 if (rpc__naf_addr_compare(addr, entries[i]->addr, &tmp_st)) 1906 return(false); 1907 } 1908 1909 /* no matching endpoint found 1910 */ 1911 return(true); 1912} 1913 1914 1915/* 1916 * Return the database object's id. 1917 */ 1918PRIVATE void epdb_inq_object(h_, object, status) 1919epdb_handle_t h_; 1920idl_uuid_t *object; 1921error_status_t *status; 1922{ 1923 struct db *h = (struct db *) h_; 1924 1925 SET_STATUS_OK(status); 1926 1927 *object = h->object; 1928} 1929 1930PRIVATE void epdb_delete_lookup_handle(h_, entry_handle) 1931epdb_handle_t h_; 1932ept_lookup_handle_t *entry_handle; 1933{ 1934 struct db *h = (struct db *) h_; 1935 1936 db_lock(h); 1937 1938 db_delete_context(h, entry_handle); 1939 1940 db_unlock(h); 1941} 1942