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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 31 #include "isns_server.h" 32 #include "isns_func.h" 33 #include "isns_msgq.h" 34 #include "isns_htab.h" 35 #include "isns_cache.h" 36 #include "isns_obj.h" 37 #include "isns_dd.h" 38 #include "isns_pdu.h" 39 #include "isns_qry.h" 40 41 /* 42 * external variables 43 */ 44 extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE]; 45 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; 46 extern const int NUM_OF_CHILD[MAX_OBJ_TYPE]; 47 extern const int TYPE_OF_CHILD[MAX_OBJ_TYPE][MAX_CHILD_TYPE]; 48 49 /* 50 * global variables 51 */ 52 const int TAG_RANGE[MAX_OBJ_TYPE][3] = { 53 { 0, 0 }, 54 { ENTITY_KEY, LAST_TAG_ENTITY, ENTITY_END }, 55 { ISCSI_KEY, LAST_TAG_ISCSI, ISCSI_END }, 56 { PORTAL_KEY1, LAST_TAG_PORTAL, PORTAL_END }, 57 { PG_KEY1, LAST_TAG_PG, PG_END }, 58 { DD_KEY, LAST_TAG_DD, DD_END }, 59 { DDS_KEY, LAST_TAG_DDS, DDS_END } 60 }; 61 62 /* 63 * local variables 64 */ 65 typedef int (*qry_func_t)(lookup_ctrl_t *); 66 67 /* Edge functions of each adjacent object */ 68 static int qry_c2e(lookup_ctrl_t *); 69 static int qry_ds2m(lookup_ctrl_t *); 70 static int qry_slf(lookup_ctrl_t *); 71 static int qry_e2i(lookup_ctrl_t *); 72 static int qry_e2p(lookup_ctrl_t *); 73 static int qry_e2g(lookup_ctrl_t *); 74 static int qry_i2g(lookup_ctrl_t *); 75 static int qry_i2d(lookup_ctrl_t *); 76 static int qry_p2g(lookup_ctrl_t *); 77 static int qry_g2i(lookup_ctrl_t *); 78 static int qry_g2p(lookup_ctrl_t *); 79 static int qry_d2s(lookup_ctrl_t *); 80 81 /* The directed cyclic graph of query procedure. */ 82 /* __|____e_________i_________p_________g_________d_________s____ */ 83 /* e | qry_slf...qry_e2i...qry_e2p...qry_e2g...NULL......NULL.... */ 84 /* i | qry_c2e...qry_slf...NULL......qry_i2g...qry_i2d...NULL.... */ 85 /* p | qry_c2e...NULL......qry_slf...qry_p2g...NULL......NULL.... */ 86 /* g | qry_c2e...qry_g2i...qry_g2p...qry_slf...NULL......NULL.... */ 87 /* d | NULL......qry_ds2m..NULL......NULL......qry_slf...qry_d2s. */ 88 /* s | NULL......NULL......NULL......NULL......qry_ds2m..qry_slf. */ 89 90 /* The type of spanning tree of query graph. */ 91 typedef struct adjvex { 92 qry_func_t f; 93 isns_type_t t; 94 struct adjvex const *v; 95 } adjvex_t; 96 97 /* The solid edges in the spanning tree. */ 98 static const adjvex_t v_slf = { &qry_slf, 0, NULL }; 99 static const adjvex_t v_c2e = { &qry_c2e, OBJ_ENTITY, NULL }; 100 static const adjvex_t v_e2i = { &qry_e2i, OBJ_ISCSI, NULL }; 101 static const adjvex_t v_e2p = { &qry_e2p, OBJ_PORTAL, NULL }; 102 static const adjvex_t v_e2g = { &qry_e2g, OBJ_PG, NULL }; 103 static const adjvex_t v_i2g = { &qry_i2g, OBJ_PG, NULL }; 104 static const adjvex_t v_i2d = { &qry_i2d, OBJ_DD, NULL }; 105 static const adjvex_t v_p2g = { &qry_p2g, OBJ_PG, NULL }; 106 static const adjvex_t v_g2i = { &qry_g2i, OBJ_ISCSI, NULL }; 107 static const adjvex_t v_g2p = { &qry_g2p, OBJ_PORTAL, NULL }; 108 static const adjvex_t v_d2s = { &qry_d2s, OBJ_DDS, NULL }; 109 static const adjvex_t v_d2i = { &qry_ds2m, OBJ_ISCSI, NULL }; 110 static const adjvex_t v_s2d = { &qry_ds2m, OBJ_DD, NULL }; 111 112 /* The virtual edges in the spanning tree. */ 113 static const adjvex_t v_i2p = { &qry_i2g, OBJ_PG, &v_g2p }; 114 static const adjvex_t v_i2s = { &qry_i2d, OBJ_DD, &v_d2s }; 115 116 static const adjvex_t v_g2d = { &qry_g2i, OBJ_ISCSI, &v_i2d }; 117 static const adjvex_t v_g2s = { &qry_g2i, OBJ_ISCSI, &v_i2s }; 118 119 static const adjvex_t v_p2i = { &qry_p2g, OBJ_PG, &v_g2i }; 120 static const adjvex_t v_p2d = { &qry_p2g, OBJ_PG, &v_g2d }; 121 static const adjvex_t v_p2s = { &qry_p2g, OBJ_PG, &v_g2s }; 122 123 static const adjvex_t v_e2d = { &qry_e2i, OBJ_ISCSI, &v_i2d }; 124 static const adjvex_t v_e2s = { &qry_e2i, OBJ_ISCSI, &v_i2s }; 125 126 static const adjvex_t v_d2e = { &qry_ds2m, OBJ_ISCSI, &v_c2e }; 127 static const adjvex_t v_d2p = { &qry_ds2m, OBJ_ISCSI, &v_i2p }; 128 static const adjvex_t v_d2g = { &qry_ds2m, OBJ_ISCSI, &v_i2g }; 129 130 static const adjvex_t v_s2e = { &qry_ds2m, OBJ_DD, &v_d2e }; 131 static const adjvex_t v_s2i = { &qry_ds2m, OBJ_DD, &v_d2i }; 132 static const adjvex_t v_s2p = { &qry_ds2m, OBJ_DD, &v_d2p }; 133 static const adjvex_t v_s2g = { &qry_ds2m, OBJ_DD, &v_d2g }; 134 135 /* the vector of query graph */ 136 static const adjvex_t *qry_puzzle[MAX_OBJ_TYPE][MAX_OBJ_TYPE] = { 137 { NULL }, 138 { NULL, &v_slf, &v_e2i, &v_e2p, &v_e2g, &v_e2d, &v_e2s }, 139 { NULL, &v_c2e, &v_slf, &v_i2p, &v_i2g, &v_i2d, &v_i2s }, 140 { NULL, &v_c2e, &v_p2i, &v_slf, &v_p2g, &v_p2d, &v_p2s }, 141 { NULL, &v_c2e, &v_g2i, &v_g2p, &v_slf, &v_g2d, &v_g2s }, 142 { NULL, &v_d2e, &v_d2i, &v_d2p, &v_d2g, &v_slf, &v_d2s }, 143 { NULL, &v_s2e, &v_s2i, &v_s2p, &v_s2g, &v_s2d, &v_slf } 144 }; 145 146 static int 147 cb_qry_parent_uid( 148 void *p1, 149 /* LINTED E_FUNC_ARG_UNUSED */ 150 void *p2 151 ) 152 { 153 uint32_t puid = get_parent_uid((isns_obj_t *)p1); 154 return ((int)puid); 155 } 156 157 static int 158 cb_qry_child_uids( 159 void *p1, 160 void *p2 161 ) 162 { 163 isns_obj_t *obj = (isns_obj_t *)p1; 164 lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; 165 isns_type_t type = lcp->data[1].ui; 166 uint32_t *uidp = get_child_t(obj, type); 167 uint32_t num = 0; 168 uint32_t *p; 169 170 if (uidp != NULL && *uidp > 0) { 171 num = *uidp; 172 p = malloc(num * sizeof (*p)); 173 if (p != NULL) { 174 uidp ++; 175 (void) memcpy(p, uidp, num * sizeof (*p)); 176 lcp->id[2] = num; 177 lcp->data[2].ptr = (uchar_t *)p; 178 } else { 179 return (ISNS_RSP_INTERNAL_ERROR); 180 } 181 } 182 183 return (0); 184 } 185 186 static int 187 e2c( 188 lookup_ctrl_t *lcp, 189 isns_type_t type 190 ) 191 { 192 int ec = 0; 193 194 uint32_t uid = lcp->curr_uid; /* last child */ 195 uint32_t num_of_child; 196 uint32_t *uids; 197 198 uint32_t tmp_uid = 0; 199 200 /* the first times of query */ 201 if (uid == 0) { 202 lcp->data[1].ui = type; 203 ec = cache_lookup(lcp, NULL, cb_qry_child_uids); 204 } 205 206 num_of_child = lcp->id[2]; 207 uids = (uint32_t *)lcp->data[2].ptr; 208 209 while (num_of_child > 0) { 210 if (*uids > uid) { 211 tmp_uid = *uids; 212 break; 213 } 214 uids ++; 215 num_of_child --; 216 } 217 218 uid = tmp_uid; 219 220 /* no more child, clean up memory */ 221 if (uid == 0) { 222 lcp->data[1].ui = 0; 223 lcp->id[2] = 0; 224 lcp->data[2].ptr = NULL; 225 226 /* free up the memory */ 227 free(uids); 228 } 229 230 /* save it for returning and querying next uid */ 231 lcp->curr_uid = uid; 232 233 return (ec); 234 } 235 236 static int 237 qry_c2e( 238 lookup_ctrl_t *lcp 239 ) 240 { 241 uint32_t uid; 242 243 /* child object has only one parent */ 244 if (lcp->curr_uid == 0) { 245 uid = (uint32_t)cache_lookup(lcp, NULL, 246 cb_qry_parent_uid); 247 } else { 248 uid = 0; 249 } 250 251 /* save the result for returnning */ 252 lcp->curr_uid = uid; 253 254 return (0); 255 } 256 257 static int 258 qry_ds2m( 259 lookup_ctrl_t *lcp 260 ) 261 { 262 int ec = 0; 263 264 uint32_t uid = lcp->curr_uid; /* last member */ 265 isns_type_t type = lcp->type; 266 uint32_t ds_id = lcp->data[0].ui; 267 268 uint32_t tmp_uid; 269 270 uint32_t n; 271 bmp_t *p; 272 273 /* the first times of query */ 274 if (uid == 0) { 275 ec = (type == OBJ_DD) ? 276 get_dd_matrix(ds_id, &p, &n) : 277 get_dds_matrix(ds_id, &p, &n); 278 lcp->id[1] = n; 279 lcp->data[1].ptr = (uchar_t *)p; 280 } else { 281 n = lcp->id[1]; 282 p = (bmp_t *)lcp->data[1].ptr; 283 } 284 285 FOR_EACH_MEMBER(p, n, tmp_uid, { 286 if (tmp_uid > uid) { 287 lcp->curr_uid = tmp_uid; 288 return (ec); 289 } 290 }); 291 292 /* no more member, clean up memory */ 293 lcp->id[1] = 0; 294 lcp->data[1].ptr = NULL; 295 296 /* free up the matrix */ 297 free(p); 298 299 lcp->curr_uid = 0; 300 301 return (ec); 302 } 303 304 static int 305 qry_slf( 306 lookup_ctrl_t *lcp 307 ) 308 { 309 uint32_t uid; 310 311 if (lcp->curr_uid == 0) { 312 uid = lcp->data[0].ui; 313 } else { 314 uid = 0; 315 } 316 317 lcp->curr_uid = uid; 318 319 return (0); 320 } 321 322 static int 323 qry_e2i( 324 lookup_ctrl_t *lcp 325 ) 326 { 327 return (e2c(lcp, OBJ_ISCSI)); 328 } 329 330 static int 331 qry_e2p( 332 lookup_ctrl_t *lcp 333 ) 334 { 335 return (e2c(lcp, OBJ_PORTAL)); 336 } 337 338 static int 339 qry_e2g( 340 lookup_ctrl_t *lcp 341 ) 342 { 343 uint32_t uid = lcp->curr_uid; /* last pg */ 344 345 htab_t *htab = cache_get_htab(OBJ_PG); 346 347 lookup_ctrl_t lc; 348 uint32_t puid; 349 350 SET_UID_LCP(&lc, OBJ_PG, 0); 351 352 /* this is a shortcut */ 353 FOR_EACH_ITEM(htab, uid, { 354 lc.data[0].ui = uid; 355 puid = (uint32_t)cache_lookup(&lc, NULL, 356 cb_qry_parent_uid); 357 if (puid == lcp->data[0].ui) { 358 /* keep the current uid */ 359 lcp->curr_uid = uid; 360 return (0); 361 } 362 }); 363 364 lcp->curr_uid = 0; 365 366 return (0); 367 } 368 369 static int 370 qry_i2g( 371 lookup_ctrl_t *lcp 372 ) 373 { 374 int ec = 0; 375 376 uint32_t uid = lcp->curr_uid; /* last pg */ 377 lookup_ctrl_t lc; 378 379 /* the first times of query */ 380 if (uid == 0) { 381 lcp->id[1] = ISNS_ISCSI_NAME_ATTR_ID; 382 ec = cache_lookup(lcp, NULL, cb_clone_attrs); 383 } 384 385 if (lcp->data[1].ptr != NULL) { 386 /* pg lookup */ 387 lc.curr_uid = uid; 388 lc.type = OBJ_PG; 389 lc.id[0] = ATTR_INDEX_PG(ISNS_PG_ISCSI_NAME_ATTR_ID); 390 lc.op[0] = OP_STRING; 391 lc.data[0].ptr = lcp->data[1].ptr; 392 lc.op[1] = 0; 393 394 uid = is_obj_there(&lc); 395 } else { 396 uid = 0; 397 } 398 399 /* no more pg, update lcp with pg object */ 400 if (uid == 0) { 401 lcp->id[1] = 0; 402 403 /* clean up the memory */ 404 if (lcp->data[1].ptr != NULL) { 405 free(lcp->data[1].ptr); 406 /* reset it */ 407 lcp->data[1].ptr = NULL; 408 } 409 } 410 411 /* save it for returning and querying next pg */ 412 lcp->curr_uid = uid; 413 414 return (ec); 415 } 416 417 static int 418 qry_i2d( 419 lookup_ctrl_t *lcp 420 ) 421 { 422 uint32_t dd_id = lcp->curr_uid; /* last dd_id */ 423 uint32_t uid = lcp->data[0].ui; 424 425 dd_id = get_dd_id(uid, dd_id); 426 427 /* save it for returning and getting next dd */ 428 lcp->curr_uid = dd_id; 429 430 return (0); 431 } 432 433 static int 434 qry_p2g( 435 lookup_ctrl_t *lcp 436 ) 437 { 438 int ec = 0; 439 440 uint32_t uid = lcp->curr_uid; /* last pg */ 441 lookup_ctrl_t lc; 442 443 /* the first time of query */ 444 if (uid == 0) { 445 /* use 1&2 for the portal ip address & port */ 446 lcp->id[1] = ISNS_PORTAL_IP_ADDR_ATTR_ID; 447 lcp->id[2] = ISNS_PORTAL_PORT_ATTR_ID; 448 ec = cache_lookup(lcp, NULL, cb_clone_attrs); 449 } 450 451 if (lcp->data[1].ip != NULL) { 452 /* pg lookup */ 453 lc.curr_uid = uid; 454 lc.type = OBJ_PG; 455 lc.id[0] = ATTR_INDEX_PG(ISNS_PG_PORTAL_IP_ADDR_ATTR_ID); 456 lc.op[0] = OP_MEMORY_IP6; 457 lc.data[0].ip = lcp->data[1].ip; 458 lc.id[1] = ATTR_INDEX_PG(ISNS_PG_PORTAL_PORT_ATTR_ID); 459 lc.op[1] = OP_INTEGER; 460 lc.data[1].ui = lcp->data[2].ui; 461 lc.op[2] = 0; 462 463 uid = is_obj_there(&lc); 464 } else { 465 uid = 0; 466 } 467 468 /* no more pg, clean up memory */ 469 if (uid == 0) { 470 lcp->id[1] = 0; 471 lcp->id[2] = 0; 472 473 /* clean up the memory */ 474 if (lcp->data[1].ip != NULL) { 475 free(lcp->data[1].ip); 476 /* reset it */ 477 lcp->data[1].ip = NULL; 478 } 479 lcp->data[2].ui = 0; 480 } 481 482 /* save it for returning and next query */ 483 lcp->curr_uid = uid; 484 485 return (ec); 486 } 487 488 static int 489 qry_g2i( 490 lookup_ctrl_t *lcp 491 ) 492 { 493 int ec = 0; 494 495 uint32_t uid = lcp->curr_uid; /* last node */ 496 lookup_ctrl_t lc; 497 498 /* the first time of query */ 499 if (uid == 0) { 500 /* use slot 1 for the storage node name */ 501 lcp->id[1] = ISNS_PG_ISCSI_NAME_ATTR_ID; 502 ec = cache_lookup(lcp, NULL, cb_clone_attrs); 503 504 if (lcp->data[1].ptr != NULL) { 505 /* iscsi node lookup */ 506 lc.curr_uid = uid; 507 lc.type = OBJ_ISCSI; 508 lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); 509 lc.op[0] = OP_STRING; 510 lc.data[0].ptr = lcp->data[1].ptr; 511 lc.op[1] = 0; 512 513 uid = is_obj_there(&lc); 514 515 /* no longer need it, clean it up */ 516 free(lcp->data[1].ptr); 517 lcp->data[1].ptr = NULL; 518 } 519 /* no longer need it, reset it */ 520 lcp->id[1] = 0; 521 } else { 522 /* one pg has maximum number of one storage node */ 523 uid = 0; 524 } 525 526 /* save it for returning and next query */ 527 lcp->curr_uid = uid; 528 529 return (ec); 530 } 531 532 static int 533 qry_g2p( 534 lookup_ctrl_t *lcp 535 ) 536 { 537 int ec = 0; 538 539 uint32_t uid = lcp->curr_uid; /* last portal */ 540 lookup_ctrl_t lc; 541 542 /* the first times of query */ 543 if (uid == 0) { 544 /* use 1&2 for the portal ip addr and port */ 545 lcp->id[1] = ISNS_PG_PORTAL_IP_ADDR_ATTR_ID; 546 lcp->id[2] = ISNS_PG_PORTAL_PORT_ATTR_ID; 547 ec = cache_lookup(lcp, NULL, cb_clone_attrs); 548 549 if (lcp->data[1].ip != NULL) { 550 /* portal lookup */ 551 lc.curr_uid = uid; 552 lc.type = OBJ_PORTAL; 553 lc.id[0] = ATTR_INDEX_PORTAL( 554 ISNS_PORTAL_IP_ADDR_ATTR_ID); 555 lc.op[0] = OP_MEMORY_IP6; 556 lc.data[0].ip = lcp->data[1].ip; 557 lc.id[1] = ATTR_INDEX_PORTAL( 558 ISNS_PORTAL_PORT_ATTR_ID); 559 lc.op[1] = OP_INTEGER; 560 lc.data[1].ui = lcp->data[2].ui; 561 lc.op[2] = 0; 562 563 uid = is_obj_there(&lc); 564 565 /* no longer need it, reset it */ 566 free(lcp->data[1].ip); 567 lcp->data[1].ip = NULL; 568 } 569 /* no longer need it, reset it */ 570 lcp->id[1] = 0; 571 lcp->id[2] = 0; 572 lcp->data[2].ui = 0; 573 } else { 574 /* one pg has maximum number of one portal */ 575 uid = 0; 576 } 577 578 /* save it for returning and next query */ 579 lcp->curr_uid = uid; 580 581 return (ec); 582 } 583 584 static int 585 qry_d2s( 586 lookup_ctrl_t *lcp 587 ) 588 { 589 uint32_t dds_id = lcp->curr_uid; /* last dds */ 590 uint32_t dd_id = lcp->data[0].ui; 591 592 dds_id = get_dds_id(dd_id, dds_id); 593 594 /* save it for returning and for getting next dds */ 595 lcp->curr_uid = dds_id; 596 597 return (0); 598 } 599 600 int 601 validate_qry_key( 602 isns_type_t type, 603 isns_tlv_t *key, 604 uint16_t key_len, 605 isns_attr_t *attrs 606 ) 607 { 608 int ec = 0; 609 610 uint32_t tag; 611 uint32_t min_tag, max_tag; 612 613 isns_attr_t *attr; 614 615 min_tag = TAG_RANGE[type][0]; 616 max_tag = TAG_RANGE[type][2]; 617 618 while (key_len != 0 && ec == 0) { 619 tag = key->attr_id; 620 if (tag < min_tag || tag > max_tag) { 621 ec = ISNS_RSP_MSG_FORMAT_ERROR; 622 } else if (key->attr_len > 0 && attrs != NULL) { 623 attr = &attrs[tag - min_tag]; /* ATTR_INDEX_xxx */ 624 ec = extract_attr(attr, key, 0); 625 if (ec == ISNS_RSP_INVALID_REGIS) { 626 ec = ISNS_RSP_MSG_FORMAT_ERROR; 627 } 628 } 629 NEXT_TLV(key, key_len); 630 } 631 632 return (ec); 633 } 634 635 static lookup_method_t 636 get_op_method( 637 uint32_t tag 638 ) 639 { 640 lookup_method_t method = 0; 641 642 switch (tag) { 643 /* OP_STRING */ 644 case ISNS_EID_ATTR_ID: 645 case ISNS_PORTAL_NAME_ATTR_ID: 646 case ISNS_ISCSI_ALIAS_ATTR_ID: 647 case ISNS_DD_SET_NAME_ATTR_ID: 648 case ISNS_DD_NAME_ATTR_ID: 649 case ISNS_ISCSI_NAME_ATTR_ID: 650 case ISNS_PG_ISCSI_NAME_ATTR_ID: 651 case ISNS_ISCSI_AUTH_METHOD_ATTR_ID: 652 method = OP_STRING; 653 break; 654 /* OP_MEMORY_IP6 */ 655 case ISNS_MGMT_IP_ADDR_ATTR_ID: 656 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 657 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 658 method = OP_MEMORY_IP6; 659 break; 660 /* OP_INTEGER */ 661 case ISNS_ENTITY_PROTOCOL_ATTR_ID: 662 case ISNS_VERSION_RANGE_ATTR_ID: 663 case ISNS_ENTITY_REG_PERIOD_ATTR_ID: 664 case ISNS_ENTITY_INDEX_ATTR_ID: 665 case ISNS_PORTAL_PORT_ATTR_ID: 666 case ISNS_ESI_INTERVAL_ATTR_ID: 667 case ISNS_ESI_PORT_ATTR_ID: 668 case ISNS_PORTAL_INDEX_ATTR_ID: 669 case ISNS_SCN_PORT_ATTR_ID: 670 case ISNS_ISCSI_NODE_TYPE_ATTR_ID: 671 case ISNS_ISCSI_SCN_BITMAP_ATTR_ID: 672 case ISNS_ISCSI_NODE_INDEX_ATTR_ID: 673 case ISNS_PG_PORTAL_PORT_ATTR_ID: 674 case ISNS_PG_TAG_ATTR_ID: 675 case ISNS_PG_INDEX_ATTR_ID: 676 case ISNS_DD_SET_ID_ATTR_ID: 677 case ISNS_DD_SET_STATUS_ATTR_ID: 678 case ISNS_DD_ID_ATTR_ID: 679 /* all other attrs */ 680 default: 681 method = OP_INTEGER; 682 break; 683 } 684 685 return (method); 686 } 687 688 static int 689 cb_attrs_match( 690 void *p1, 691 void *p2 692 ) 693 { 694 isns_obj_t *obj = (isns_obj_t *)p1; 695 isns_attr_t *attrs = (isns_attr_t *) 696 ((lookup_ctrl_t *)p2)->data[1].ptr; 697 698 lookup_ctrl_t lc; 699 int match = 1; /* 0: not match, otherwise: match */ 700 701 int i; 702 703 lc.op[1] = 0; 704 705 for (i = 0; match != 0 && i < NUM_OF_ATTRS[obj->type]; i++) { 706 if (attrs->tag != 0 && attrs->len > 0) { 707 lc.id[0] = i; 708 lc.op[0] = get_op_method(attrs->tag); 709 lc.data[0].ptr = attrs->value.ptr; 710 match = key_cmp(&lc, obj) == 0 ? 1 : 0; 711 } 712 attrs ++; 713 } 714 715 return (match); 716 } 717 718 static int 719 attrs_match( 720 isns_type_t type, 721 uint32_t uid, 722 isns_attr_t *attrs 723 ) 724 { 725 int match; /* 0: not match, otherwise: match */ 726 lookup_ctrl_t lc; 727 728 SET_UID_LCP(&lc, type, uid); 729 730 lc.data[1].ptr = (uchar_t *)attrs; 731 732 match = cache_lookup(&lc, NULL, cb_attrs_match); 733 734 return (match); 735 } 736 737 static int 738 insert_uid( 739 uint32_t **pp, 740 uint32_t *np, 741 uint32_t *sp, 742 uint32_t uid 743 ) 744 { 745 int ec = 0; 746 747 uint32_t *p = *pp; 748 uint32_t n = *np; 749 uint32_t s = *sp; 750 751 uint32_t u; 752 uint32_t *t; 753 754 /* check for duplication */ 755 if (n > 0 && uid <= p[n - 1]) { 756 while (n-- > 0) { 757 if (p[n] == uid) { 758 return (0); 759 } 760 } 761 n = *np; 762 u = p[n - 1]; 763 p[n - 1] = uid; 764 uid = u; 765 } 766 767 768 if (s == n) { 769 s = (s == 0) ? 8 : s * 2; 770 t = (uint32_t *)realloc(p, s * sizeof (uint32_t)); 771 if (t != NULL) { 772 p = t; 773 *pp = p; 774 *sp = s; 775 } else { 776 ec = ISNS_RSP_INTERNAL_ERROR; 777 } 778 } 779 780 if (ec == 0) { 781 p[n ++] = uid; 782 *np = n; 783 } 784 785 return (ec); 786 } 787 788 static int 789 qry_and_match( 790 uint32_t **obj_uids, 791 uint32_t *num_of_objs, 792 uint32_t *size, 793 isns_type_t type, 794 uint32_t src_uid, 795 isns_type_t src_type, 796 isns_attr_t *attrs 797 ) 798 { 799 int ec = 0; 800 801 lookup_ctrl_t lc = { 0 }; /* !!! need to be empty */ 802 uint32_t uid; 803 804 const adjvex_t *vex; 805 806 /* circular list */ 807 uint32_t *p[2], n[2], s[2]; 808 int i, j; 809 810 uint32_t *p1, n1; 811 uint32_t *p2, n2, s2; 812 isns_type_t t; 813 814 /* initialize the circular list */ 815 i = 0; 816 j = 1; 817 818 p[i] = *obj_uids; 819 n[i] = *num_of_objs; 820 s[i] = *size; 821 822 p[j] = malloc(8 * sizeof (uint32_t)); 823 p[j][0] = src_uid; 824 n[j] = 1; 825 s[j] = 8; 826 827 /* initial object type of being queried */ 828 t = src_type; 829 830 vex = qry_puzzle[src_type][type]; 831 832 do { 833 /* shift one on the circular list */ 834 i = (i + 1) & 1; 835 j = (j + 1) & 1; 836 837 p1 = p[i]; n1 = n[i]; 838 p2 = p[j]; n2 = n[j]; s2 = s[j]; 839 840 /* prepare lookup control */ 841 lc.type = t; 842 lc.id[0] = UID_ATTR_INDEX[t]; 843 lc.op[0] = OP_INTEGER; 844 845 /* result object type */ 846 t = vex->t; 847 848 FOR_EACH_OBJS(p1, n1, uid, { 849 /* start query */ 850 lc.data[0].ui = uid; 851 ec = vex->f(&lc); 852 uid = lc.curr_uid; 853 while (ec == 0 && uid != 0) { 854 if (attrs == NULL || 855 attrs_match(type, uid, attrs) != 0) { 856 ec = insert_uid(&p2, &n2, &s2, uid); 857 } 858 if (ec == 0) { 859 ec = vex->f(&lc); 860 uid = lc.curr_uid; 861 } else { 862 n1 = n2 = 0; /* force break */ 863 } 864 } 865 }); 866 if (ec == 0) { 867 vex = vex->v; 868 } else { 869 vex = NULL; /* force break */ 870 } 871 /* push back */ 872 p[j] = p2; n[j] = n2; s[j] = s2; 873 /* reset the number of objects */ 874 n[i] = 0; 875 } while (vex != NULL); 876 877 /* clean up the memory */ 878 free(p1); 879 if (ec != 0) { 880 free(p2); 881 p2 = NULL; 882 n2 = 0; 883 s2 = 0; 884 } 885 886 *obj_uids = p2; 887 *num_of_objs = n2; 888 *size = s2; 889 890 return (ec); 891 } 892 893 int 894 get_qry_keys( 895 bmp_t *nodes_bmp, 896 uint32_t num_of_nodes, 897 isns_type_t *type, 898 isns_tlv_t *key, 899 uint16_t key_len, 900 uint32_t **obj_uids, 901 uint32_t *num_of_objs 902 ) 903 { 904 int ec = 0; 905 union { 906 isns_obj_t o; 907 isns_entity_t e; 908 isns_iscsi_t i; 909 isns_portal_t p; 910 isns_pg_t g; 911 isns_dd_t d; 912 isns_dds_t s; 913 } an_obj = { 0 }; 914 isns_attr_t *attrs; 915 916 htab_t *htab; 917 uint32_t node_uid; 918 919 uint32_t size; 920 921 *obj_uids = NULL; 922 *num_of_objs = 0; 923 size = 0; 924 925 /* get the object type identified by the key */ 926 *type = TLV2TYPE(key); 927 if (*type == 0) { 928 return (ISNS_RSP_INVALID_QRY); 929 } 930 931 attrs = &an_obj.o.attrs[0]; 932 /* validate the Message Key */ 933 ec = validate_qry_key(*type, key, key_len, attrs); 934 if (ec != 0) { 935 return (ec); 936 } 937 938 if (nodes_bmp != NULL) { 939 FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, { 940 ec = qry_and_match( 941 obj_uids, num_of_objs, &size, *type, 942 node_uid, OBJ_ISCSI, attrs); 943 if (ec != 0) { 944 return (ec); 945 } 946 }); 947 } else { 948 node_uid = 0; 949 htab = cache_get_htab(OBJ_ISCSI); 950 FOR_EACH_ITEM(htab, node_uid, { 951 ec = qry_and_match( 952 obj_uids, num_of_objs, &size, *type, 953 node_uid, OBJ_ISCSI, attrs); 954 if (ec != 0) { 955 return (ec); 956 } 957 }); 958 } 959 960 return (ec); 961 } 962 963 int 964 get_qry_ops( 965 uint32_t uid, 966 isns_type_t src_type, 967 isns_type_t op_type, 968 uint32_t **op_uids, 969 uint32_t *num_of_ops, 970 uint32_t *size 971 ) 972 { 973 int ec = 0; 974 975 *num_of_ops = 0; 976 977 ec = qry_and_match( 978 op_uids, num_of_ops, size, op_type, 979 uid, src_type, NULL); 980 981 return (ec); 982 } 983 984 int 985 get_qry_ops2( 986 uint32_t *nodes_bmp, 987 uint32_t num_of_nodes, 988 isns_type_t op_type, 989 uint32_t **op_uids, 990 uint32_t *num_of_ops, 991 uint32_t *size 992 ) 993 { 994 int ec = 0; 995 996 uint32_t node_uid; 997 998 htab_t *htab; 999 1000 *num_of_ops = 0; 1001 1002 if (nodes_bmp != NULL) { 1003 FOR_EACH_MEMBER(nodes_bmp, num_of_nodes, node_uid, { 1004 ec = qry_and_match( 1005 op_uids, num_of_ops, size, op_type, 1006 node_uid, OBJ_ISCSI, NULL); 1007 if (ec != 0) { 1008 return (ec); 1009 } 1010 }); 1011 } else { 1012 node_uid = 0; 1013 htab = cache_get_htab(OBJ_ISCSI); 1014 FOR_EACH_ITEM(htab, node_uid, { 1015 ec = qry_and_match( 1016 op_uids, num_of_ops, size, op_type, 1017 node_uid, OBJ_ISCSI, NULL); 1018 if (ec != 0) { 1019 return (ec); 1020 } 1021 }); 1022 } 1023 1024 return (ec); 1025 } 1026 1027 uint32_t 1028 get_next_obj( 1029 isns_tlv_t *tlv, 1030 uint32_t tlv_len, 1031 isns_type_t type, 1032 uint32_t *uids, 1033 uint32_t num 1034 ) 1035 { 1036 lookup_ctrl_t lc; 1037 1038 uint32_t tag; 1039 uint8_t *value; 1040 1041 uint32_t old = 0; 1042 uint32_t min = 0; 1043 uint32_t uid, diff; 1044 uint32_t pre_diff = 0xFFFFFFFF; 1045 1046 lc.curr_uid = 0; 1047 lc.type = type; 1048 lc.op[1] = 0; 1049 lc.op[2] = 0; 1050 1051 if (tlv_len > 8) { 1052 tag = tlv->attr_id; 1053 value = tlv->attr_value; 1054 switch (tag) { 1055 case ISNS_EID_ATTR_ID: 1056 lc.id[0] = ATTR_INDEX_ENTITY(ISNS_EID_ATTR_ID); 1057 lc.op[0] = OP_STRING; 1058 lc.data[0].ptr = (uchar_t *)value; 1059 break; 1060 case ISNS_ISCSI_NAME_ATTR_ID: 1061 lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); 1062 lc.op[0] = OP_STRING; 1063 lc.data[0].ptr = (uchar_t *)value; 1064 break; 1065 case ISNS_ISCSI_NODE_INDEX_ATTR_ID: 1066 lc.id[0] = ATTR_INDEX_ISCSI( 1067 ISNS_ISCSI_NODE_INDEX_ATTR_ID); 1068 lc.op[0] = OP_INTEGER; 1069 lc.data[0].ui = ntohl(*(uint32_t *)value); 1070 break; 1071 case ISNS_PORTAL_IP_ADDR_ATTR_ID: 1072 lc.id[0] = ATTR_INDEX_PORTAL( 1073 ISNS_PORTAL_IP_ADDR_ATTR_ID); 1074 lc.op[0] = OP_MEMORY_IP6; 1075 lc.data[0].ip = (in6_addr_t *)value; 1076 NEXT_TLV(tlv, tlv_len); 1077 if (tlv_len > 8 && 1078 ((tag = tlv->attr_id) == 1079 ISNS_PORTAL_PORT_ATTR_ID)) { 1080 value = tlv->attr_value; 1081 lc.id[1] = ATTR_INDEX_PORTAL( 1082 ISNS_PORTAL_PORT_ATTR_ID); 1083 lc.op[1] = OP_INTEGER; 1084 lc.data[1].ui = ntohl(*(uint32_t *)value); 1085 } else { 1086 return (0); 1087 } 1088 break; 1089 case ISNS_PORTAL_INDEX_ATTR_ID: 1090 lc.id[0] = ATTR_INDEX_PORTAL(ISNS_PORTAL_INDEX_ATTR_ID); 1091 lc.op[0] = OP_INTEGER; 1092 lc.data[0].ui = ntohl(*(uint32_t *)value); 1093 break; 1094 case ISNS_PG_INDEX_ATTR_ID: 1095 lc.id[0] = ATTR_INDEX_PG(ISNS_PG_INDEX_ATTR_ID); 1096 lc.op[0] = OP_INTEGER; 1097 lc.data[0].ui = ntohl(*(uint32_t *)value); 1098 break; 1099 default: 1100 return (0); 1101 } 1102 1103 old = is_obj_there(&lc); 1104 if (old == 0) { 1105 return (0); 1106 } 1107 } 1108 1109 while (num > 0) { 1110 uid = uids[-- num]; 1111 if (uid > old) { 1112 diff = uid - old; 1113 if (diff < pre_diff) { 1114 min = uid; 1115 pre_diff = diff; 1116 } 1117 } 1118 } 1119 1120 return (min); 1121 } 1122 1123 static int 1124 cb_qry_rsp( 1125 void *p1, 1126 void *p2 1127 ) 1128 { 1129 int ec = 0; 1130 1131 isns_obj_t *obj = (isns_obj_t *)p1; 1132 lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; 1133 1134 uint16_t tlv_len = lcp->id[1]; 1135 isns_tlv_t *tlv = (isns_tlv_t *)lcp->data[1].ptr; 1136 conn_arg_t *conn = (conn_arg_t *)lcp->data[2].ptr; 1137 1138 isns_type_t type = obj->type; 1139 uint32_t min_tag = TAG_RANGE[type][0]; 1140 uint32_t mid_tag = TAG_RANGE[type][1]; 1141 uint32_t max_tag = TAG_RANGE[type][2]; 1142 1143 isns_attr_t *attr; 1144 uint32_t tag; 1145 uint32_t id; 1146 uint32_t len; 1147 void *value; 1148 1149 isns_pdu_t *rsp = conn->out_packet.pdu; 1150 size_t pl = conn->out_packet.pl; 1151 size_t sz = conn->out_packet.sz; 1152 1153 do { 1154 if (tlv->attr_len == 0) { 1155 tag = tlv->attr_id; 1156 if (tag <= mid_tag) { 1157 id = ATTR_INDEX(tag, type); 1158 attr = &obj->attrs[id]; 1159 len = attr->len; 1160 value = (void *)attr->value.ptr; 1161 ec = pdu_add_tlv(&rsp, &pl, &sz, 1162 tag, len, value, 0); 1163 } 1164 } 1165 NEXT_TLV(tlv, tlv_len); 1166 } while (ec == 0 && 1167 tlv_len >= 8 && 1168 tlv->attr_id >= min_tag && 1169 tlv->attr_id <= max_tag); 1170 1171 conn->out_packet.pdu = rsp; 1172 conn->out_packet.pl = pl; 1173 conn->out_packet.sz = sz; 1174 1175 return (ec); 1176 } 1177 1178 int 1179 get_qry_attrs( 1180 uint32_t uid, 1181 isns_type_t type, 1182 isns_tlv_t *tlv, 1183 uint16_t tlv_len, 1184 conn_arg_t *conn 1185 ) 1186 { 1187 int ec = 0; 1188 1189 lookup_ctrl_t lc; 1190 1191 SET_UID_LCP(&lc, type, uid); 1192 1193 lc.id[1] = tlv_len; 1194 lc.data[1].ptr = (uchar_t *)tlv; 1195 lc.data[2].ptr = (uchar_t *)conn; 1196 1197 ec = cache_lookup(&lc, NULL, cb_qry_rsp); 1198 1199 return (ec); 1200 } 1201 1202 int 1203 get_qry_attrs1( 1204 uint32_t uid, 1205 isns_type_t type, 1206 isns_tlv_t *tlv, 1207 uint16_t tlv_len, 1208 conn_arg_t *conn 1209 ) 1210 { 1211 isns_tlv_t *tmp = tlv; 1212 uint32_t tmp_len = tlv_len; 1213 1214 /* clear the length of all of tlv */ 1215 while (tmp_len > 8) { 1216 tmp->attr_len = 0; 1217 NEXT_TLV(tmp, tmp_len); 1218 } 1219 1220 return (get_qry_attrs(uid, type, tlv, tlv_len, conn)); 1221 } 1222