1 /* $NetBSD: iscsid_lists.c,v 1.3 2011/11/20 01:23:57 agc Exp $ */ 2 3 /*- 4 * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include "iscsid_globals.h" 34 35 /* counter for initiator ID */ 36 static uint32_t initiator_id = 0; 37 38 /* -------------------------------------------------------------------------- */ 39 40 /*#ifdef ISCSI_NOTHREAD */ 41 #if 0 42 43 /* 44 * verify_session: 45 * Verify that a specific session still exists, delete it if not. 46 * 47 * Parameter: The session pointer. 48 */ 49 50 static void 51 verify_session(session_t * sess) 52 { 53 generic_entry_t *curr, *next; 54 int nosess = 0; 55 56 for (curr = sess->connections.tqh_first; curr != NULL && !nosess; curr = next) { 57 next = curr->link.tqe_next; 58 nosess = verify_connection((connection_t *) curr) == ISCSI_STATUS_INVALID_SESSION_ID; 59 } 60 61 if (!nosess && sess->num_connections) 62 return; 63 64 TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link); 65 list[SESSION_LIST].num_entries--; 66 67 while ((curr = TAILQ_FIRST(&sess->connections)) != NULL) { 68 TAILQ_REMOVE(&sess->connections, curr, link); 69 free(curr); 70 } 71 free(sess); 72 } 73 74 75 /* 76 * verify_sessions: 77 * Verify that all sessions in the list still exist. 78 */ 79 80 void 81 verify_sessions(void) 82 { 83 generic_entry_t *curr, *next; 84 85 for (curr = list[SESSION_LIST].list.tqh_first; curr != NULL; curr = next) { 86 next = curr->link.tqe_next; 87 verify_session((session_t *) curr); 88 } 89 } 90 91 #endif 92 93 /* -------------------------------------------------------------------------- */ 94 95 /* 96 * find_id: 97 * Find a list element by ID. 98 * 99 * Parameter: the list head and the ID to search for 100 * 101 * Returns: The pointer to the element (or NULL if not found) 102 */ 103 104 generic_entry_t * 105 find_id(generic_list_t * head, uint32_t id) 106 { 107 generic_entry_t *curr; 108 109 if (!id) 110 return NULL; 111 112 TAILQ_FOREACH(curr, head, link) 113 if (curr->sid.id == id) 114 break; 115 116 return curr; 117 } 118 119 /* 120 * find_name: 121 * Find a list entry by name. 122 * 123 * Parameter: the list head and the symbolic name to search for 124 * 125 * Returns: The pointer to the entry (or NULL if not found) 126 */ 127 128 generic_entry_t * 129 find_name(generic_list_t * head, uint8_t * name) 130 { 131 generic_entry_t *curr; 132 133 if (!*name) 134 return NULL; 135 136 TAILQ_FOREACH(curr, head, link) 137 if (strcmp((char *)curr->sid.name, (char *)name) == 0) 138 break; 139 140 return curr; 141 } 142 143 144 /* 145 * find_sym_id: 146 * Find a list entry by name or numeric id. 147 * 148 * Parameter: the list head and the symbolic id to search for 149 * 150 * Returns: The pointer to the entry (or NULL if not found) 151 */ 152 153 generic_entry_t * 154 find_sym_id(generic_list_t * head, iscsid_sym_id_t * sid) 155 { 156 157 if (sid->id != 0) 158 return find_id(head, sid->id); 159 160 return (sid->name[0]) ? find_name(head, sid->name) : NULL; 161 } 162 163 164 /* 165 * get_id: 166 * Get the numeric ID for a symbolic ID 167 * 168 * Parameter: the list head and the symbolic id 169 * 170 * Returns: The numeric ID (0 if not found) 171 */ 172 173 uint32_t 174 get_id(generic_list_t * head, iscsid_sym_id_t * sid) 175 { 176 generic_entry_t *ent; 177 178 if (sid->id != 0) 179 return sid->id; 180 181 ent = find_name(head, sid->name); 182 return (ent != NULL) ? ent->sid.id : 0; 183 } 184 185 186 /* 187 * find_target_name: 188 * Find a target by TargetName. 189 * 190 * Parameter: the target name 191 * 192 * Returns: The pointer to the target (or NULL if not found) 193 */ 194 195 target_t * 196 find_target(iscsid_list_kind_t lst, iscsid_sym_id_t * sid) 197 { 198 target_t *targ; 199 200 if ((targ = (target_t *)(void *)find_sym_id (&list [lst].list, sid)) != NULL) 201 return targ; 202 if (lst == TARGET_LIST) { 203 portal_t *portal; 204 205 if ((portal = (void *)find_portal (sid)) != NULL) 206 return portal->target; 207 } 208 return NULL; 209 } 210 211 212 /* 213 * find_target_name: 214 * Find a target by TargetName. 215 * 216 * Parameter: the target name 217 * 218 * Returns: The pointer to the target (or NULL if not found) 219 */ 220 221 target_t * 222 find_TargetName(iscsid_list_kind_t lst, uint8_t * name) 223 { 224 generic_entry_t *curr; 225 target_t *t = NULL; 226 227 if (lst == PORTAL_LIST) 228 lst = TARGET_LIST; 229 230 TAILQ_FOREACH(curr, &list[lst].list, link) { 231 t = (void *)curr; 232 if (strcmp((char *)t->TargetName, (char *)name) == 0) 233 break; 234 } 235 236 DEB(10, ("Find_TagetName returns %p\n", curr)); 237 238 return t; 239 } 240 241 242 /* 243 * find_portal_by_addr: 244 * Find a Portal by Address. 245 * 246 * Parameter: the associated target, and the address 247 * 248 * Returns: The pointer to the portal (or NULL if not found) 249 */ 250 251 portal_t * 252 find_portal_by_addr(target_t * target, iscsi_portal_address_t * addr) 253 { 254 generic_entry_t *curr; 255 portal_t *p = NULL; 256 257 TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) { 258 p = (void *)curr; 259 DEB(10, ("Find_portal_by_addr - addr %s port %d target %x\n", 260 p->addr.address, 261 p->addr.port, 262 (int) p->target)); 263 264 if (strcmp((char *)p->addr.address, (char *)addr->address) == 0 && 265 (!addr->port || p->addr.port == addr->port) && 266 p->target == target) 267 break; 268 } 269 270 DEB(10, ("Find_portal_by_addr returns %p\n", curr)); 271 return p; 272 } 273 274 275 /* 276 * find_send_target_by_addr: 277 * Find a Send Target by Address. 278 * 279 * Parameter: the address 280 * 281 * Returns: The pointer to the portal (or NULL if not found) 282 */ 283 284 send_target_t * 285 find_send_target_by_addr(iscsi_portal_address_t * addr) 286 { 287 generic_entry_t *curr; 288 send_target_t *t = NULL; 289 290 TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link) { 291 t = (void *)curr; 292 if (strcmp((char *)t->addr.address, (char *)addr->address) == 0 && 293 (!addr->port || t->addr.port == addr->port)) 294 break; 295 } 296 297 DEB(10, ("Find_send_target_by_addr returns %p\n", curr)); 298 return t; 299 } 300 301 302 /* 303 * get_list: 304 * Handle GET_LIST request: Return the list of IDs contained in the list. 305 * 306 * Parameter: 307 * par The request parameters. 308 * prsp Pointer to address of response buffer. 309 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 310 * for static buffer. 311 */ 312 313 void 314 get_list(iscsid_get_list_req_t * par, iscsid_response_t ** prsp, int *prsp_temp) 315 { 316 iscsid_get_list_rsp_t *res; 317 iscsid_response_t *rsp = *prsp; 318 int num; 319 uint32_t *idp; 320 generic_list_t *plist; 321 generic_entry_t *curr; 322 323 DEB(10, ("get_list, kind %d\n", par->list_kind)); 324 325 if (par->list_kind == SESSION_LIST) 326 LOCK_SESSIONS; 327 else if (par->list_kind >= NUM_DAEMON_LISTS) { 328 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 329 return; 330 } 331 332 plist = &list[par->list_kind].list; 333 num = list[par->list_kind].num_entries; 334 335 if (!num) { 336 if (par->list_kind == SESSION_LIST) 337 UNLOCK_SESSIONS; 338 rsp->status = ISCSID_STATUS_LIST_EMPTY; 339 return; 340 } 341 342 rsp = make_rsp(sizeof(iscsid_get_list_rsp_t) + 343 (num - 1) * sizeof(uint32_t), prsp, prsp_temp); 344 if (rsp == NULL) { 345 if (par->list_kind == SESSION_LIST) 346 UNLOCK_SESSIONS; 347 return; 348 } 349 /* copy the ID of all list entries */ 350 res = (iscsid_get_list_rsp_t *)(void *)rsp->parameter; 351 res->num_entries = num; 352 idp = res->id; 353 354 TAILQ_FOREACH(curr, plist, link) 355 * idp++ = curr->sid.id; 356 357 if (par->list_kind == SESSION_LIST) 358 UNLOCK_SESSIONS; 359 } 360 361 362 /* 363 * search_list: 364 * Handle SEARCH_LIST request: Search the given list for the string or 365 * address. 366 * Note: Not all combinations of list and search type make sense. 367 * 368 * Parameter: 369 * par The request parameters. 370 * prsp Pointer to address of response buffer. 371 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 372 * for static buffer. 373 */ 374 375 void 376 search_list(iscsid_search_list_req_t * par, iscsid_response_t ** prsp, 377 int *prsp_temp) 378 { 379 iscsid_response_t *rsp = *prsp; 380 generic_entry_t *elem = NULL; 381 382 DEB(10, ("search_list, list_kind %d, search_kind %d\n", 383 par->list_kind, par->search_kind)); 384 385 if (par->list_kind == SESSION_LIST) 386 LOCK_SESSIONS; 387 else if (par->list_kind >= NUM_DAEMON_LISTS) { 388 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 389 return; 390 } 391 392 if (!list[par->list_kind].num_entries) { 393 if (par->list_kind == SESSION_LIST) 394 UNLOCK_SESSIONS; 395 rsp->status = ISCSID_STATUS_NOT_FOUND; 396 return; 397 } 398 399 switch (par->search_kind) { 400 case FIND_ID: 401 elem = find_id(&list[par->list_kind].list, par->intval); 402 break; 403 404 case FIND_NAME: 405 elem = find_name(&list[par->list_kind].list, par->strval); 406 break; 407 408 case FIND_TARGET_NAME: 409 switch (par->list_kind) { 410 case TARGET_LIST: 411 case PORTAL_LIST: 412 case SEND_TARGETS_LIST: 413 elem = (void *)find_TargetName(par->list_kind, 414 par->strval); 415 break; 416 417 case SESSION_LIST: 418 TAILQ_FOREACH(elem, &list[SESSION_LIST].list, link) 419 if (strcmp((char *)((session_t *)(void *)elem)->target.TargetName, 420 (char *)par->strval) == 0) 421 break; 422 break; 423 424 default: 425 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 426 break; 427 } 428 break; 429 430 case FIND_ADDRESS: 431 switch (par->list_kind) { 432 case PORTAL_LIST: 433 TAILQ_FOREACH(elem, &list[PORTAL_LIST].list, link) { 434 portal_t *p = (void *)elem; 435 if (strcmp((char *)p->addr.address, (char *)par->strval) == 0 && 436 (!par->intval || 437 p->addr.port == par->intval)) 438 break; 439 } 440 break; 441 442 case SEND_TARGETS_LIST: 443 TAILQ_FOREACH(elem, &list[SEND_TARGETS_LIST].list, link) { 444 send_target_t *t = (void *)elem; 445 if (strcmp((char *)t->addr.address, 446 (char *)par->strval) == 0 && 447 (!par->intval || 448 t->addr.port == par->intval)) 449 break; 450 } 451 break; 452 453 case ISNS_LIST: 454 TAILQ_FOREACH(elem, &list[ISNS_LIST].list, link) { 455 isns_t *i = (void *)elem; 456 if (strcmp((char *)i->address, (char *)par->strval) == 0 && 457 (!par->intval || i->port == par->intval)) 458 break; 459 } 460 break; 461 462 default: 463 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 464 break; 465 } 466 break; 467 468 default: 469 rsp->status = ISCSID_STATUS_INVALID_PARAMETER; 470 return; 471 } 472 473 if (elem == NULL) { 474 if (par->list_kind == SESSION_LIST) 475 UNLOCK_SESSIONS; 476 rsp->status = ISCSID_STATUS_NOT_FOUND; 477 return; 478 } 479 480 rsp = make_rsp(sizeof(iscsid_sym_id_t), prsp, prsp_temp); 481 if (rsp == NULL) { 482 if (par->list_kind == SESSION_LIST) 483 UNLOCK_SESSIONS; 484 return; 485 } 486 487 (void) memcpy(rsp->parameter, &elem->sid, sizeof(elem->sid)); 488 if (par->list_kind == SESSION_LIST) 489 UNLOCK_SESSIONS; 490 } 491 492 493 /* 494 * get_session_list: 495 * Handle GET_SESSION_LIST request: Return a list of sessions complete 496 * with basic session info. 497 * 498 * Parameter: 499 * prsp Pointer to address of response buffer. 500 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 501 * for static buffer. 502 */ 503 504 void 505 get_session_list(iscsid_response_t ** prsp, int *prsp_temp) 506 { 507 iscsid_get_session_list_rsp_t *res; 508 iscsid_response_t *rsp = *prsp; 509 iscsid_session_list_entry_t *ent; 510 generic_list_t *plist; 511 generic_entry_t *curr; 512 session_t *sess; 513 connection_t *conn; 514 int num; 515 516 DEB(10, ("get_session_list\n")); 517 518 LOCK_SESSIONS; 519 plist = &list[SESSION_LIST].list; 520 num = list[SESSION_LIST].num_entries; 521 522 if (!num) { 523 UNLOCK_SESSIONS; 524 rsp->status = ISCSID_STATUS_LIST_EMPTY; 525 return; 526 } 527 528 rsp = make_rsp(sizeof(iscsid_get_session_list_rsp_t) + 529 (num - 1) * sizeof(iscsid_session_list_entry_t), 530 prsp, prsp_temp); 531 if (rsp == NULL) { 532 UNLOCK_SESSIONS; 533 return; 534 } 535 /* copy the ID of all list entries */ 536 res = (iscsid_get_session_list_rsp_t *)(void *)rsp->parameter; 537 res->num_entries = num; 538 ent = res->session; 539 540 TAILQ_FOREACH(curr, plist, link) { 541 sess = (session_t *)(void *)curr; 542 conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections); 543 544 ent->session_id = sess->entry.sid; 545 ent->first_connection_id = conn->entry.sid.id; 546 ent->num_connections = sess->num_connections; 547 ent->portal_id = conn->portal.sid.id; 548 ent->initiator_id = conn->initiator_id; 549 ent++; 550 } 551 UNLOCK_SESSIONS; 552 } 553 554 /* 555 * get_connection_list: 556 * Handle GET_CONNECTION_LIST request: Return a list of connections 557 * for a session. 558 * 559 * Parameter: 560 * prsp Pointer to address of response buffer. 561 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 562 * for static buffer. 563 */ 564 565 void 566 get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp, 567 int *prsp_temp) 568 { 569 iscsid_get_connection_list_rsp_t *res; 570 iscsid_response_t *rsp = *prsp; 571 iscsid_connection_list_entry_t *ent; 572 generic_entry_t *curr; 573 session_t *sess; 574 connection_t *conn; 575 int num; 576 577 DEB(10, ("get_connection_list\n")); 578 579 LOCK_SESSIONS; 580 if ((sess = find_session(req)) == NULL) { 581 UNLOCK_SESSIONS; 582 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 583 return; 584 } 585 586 num = sess->num_connections; 587 rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) + 588 (num - 1) * sizeof(iscsid_connection_list_entry_t), 589 prsp, prsp_temp); 590 if (rsp == NULL) { 591 UNLOCK_SESSIONS; 592 return; 593 } 594 /* copy the ID of all list entries */ 595 res = (iscsid_get_connection_list_rsp_t *)(void *)rsp->parameter; 596 res->num_connections = num; 597 ent = res->connection; 598 599 TAILQ_FOREACH(curr, &sess->connections, link) { 600 conn = (connection_t *)(void *)curr; 601 ent->connection_id = conn->entry.sid; 602 ent->target_portal_id = conn->portal.sid; 603 ent->target_portal = conn->portal.addr; 604 ent++; 605 } 606 UNLOCK_SESSIONS; 607 } 608 609 610 /* 611 * get_connection_info: 612 * Handle GET_CONNECTION_INFO request: Return information about a connection 613 * 614 * Parameter: 615 * par The request parameters. 616 * prsp Pointer to address of response buffer. 617 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 618 * for static buffer. 619 */ 620 621 void 622 get_connection_info(iscsid_get_connection_info_req_t * req, 623 iscsid_response_t ** prsp, int *prsp_temp) 624 { 625 iscsid_get_connection_info_rsp_t *res; 626 iscsid_response_t *rsp = *prsp; 627 session_t *sess; 628 connection_t *conn; 629 initiator_t *init = NULL; 630 631 DEB(10, ("get_connection_info, session %d, connection %d\n", 632 req->session_id.id, req->connection_id.id)); 633 634 LOCK_SESSIONS; 635 if ((sess = find_session(&req->session_id)) == NULL) { 636 UNLOCK_SESSIONS; 637 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 638 return; 639 } 640 if (!req->connection_id.id && !req->connection_id.name[0]) { 641 conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections); 642 } else if ((conn = find_connection(sess, &req->connection_id)) == NULL) { 643 UNLOCK_SESSIONS; 644 rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID; 645 return; 646 } 647 648 rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp); 649 if (rsp == NULL) { 650 UNLOCK_SESSIONS; 651 return; 652 } 653 654 if (conn->initiator_id) 655 init = find_initiator_id(conn->initiator_id); 656 657 res = (iscsid_get_connection_info_rsp_t *)(void *)rsp->parameter; 658 659 res->session_id = sess->entry.sid; 660 res->connection_id = conn->entry.sid; 661 res->target_portal_id = conn->portal.sid; 662 res->target_portal = conn->portal.addr; 663 strlcpy((char *)res->TargetName, (char *)conn->target.TargetName, 664 sizeof(res->TargetName)); 665 strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias, 666 sizeof(res->TargetAlias)); 667 if (init != NULL) { 668 res->initiator_id = init->entry.sid; 669 strlcpy((char *)res->initiator_address, (char *)init->address, 670 sizeof(res->initiator_address)); 671 } 672 UNLOCK_SESSIONS; 673 } 674 675 /* ------------------------------------------------------------------------- */ 676 677 /* 678 * find_initator_by_addr: 679 * Find an Initiator Portal by Address. 680 * 681 * Parameter: the address 682 * 683 * Returns: The pointer to the portal (or NULL if not found) 684 */ 685 686 static initiator_t * 687 find_initiator_by_addr(uint8_t * addr) 688 { 689 generic_entry_t *curr; 690 initiator_t *i = NULL; 691 692 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 693 i = (void *)curr; 694 if (strcmp((char *)i->address, (char *)addr) == 0) 695 break; 696 } 697 698 DEB(9, ("Find_initiator_by_addr returns %p\n", curr)); 699 return i; 700 } 701 702 703 /* 704 * add_initiator_portal: 705 * Add an initiator portal. 706 * 707 * Parameter: 708 * par The request parameters. 709 * prsp Pointer to address of response buffer. 710 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 711 * for static buffer. 712 */ 713 714 void 715 add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp, 716 int *prsp_temp) 717 { 718 iscsid_add_initiator_rsp_t *res; 719 iscsid_response_t *rsp = *prsp; 720 initiator_t *init; 721 722 DEB(9, ("AddInitiatorPortal '%s' (name '%s')\n", par->address, par->name)); 723 724 if (find_initiator_by_addr(par->address) != NULL) { 725 rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY; 726 return; 727 } 728 729 if (find_initiator_name(par->name) != NULL) { 730 rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 731 return; 732 } 733 734 if ((init = calloc(1, sizeof(*init))) == NULL) { 735 rsp->status = ISCSID_STATUS_NO_RESOURCES; 736 return; 737 } 738 739 DEB(9, ("AddInitiatorPortal initiator_id = %d\n", initiator_id)); 740 741 for (initiator_id++; 742 !initiator_id || find_initiator_id(initiator_id) != NULL;) 743 initiator_id++; 744 745 init->entry.sid.id = initiator_id; 746 strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name)); 747 strlcpy((char *)init->address, (char *)par->address, sizeof(init->address)); 748 749 rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp); 750 if (rsp == NULL) 751 return; 752 753 LOCK_SESSIONS; 754 TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link); 755 list[INITIATOR_LIST].num_entries++; 756 UNLOCK_SESSIONS; 757 758 res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter; 759 res->portal_id = init->entry.sid.id; 760 } 761 762 763 /* 764 * remove_initiator_portal: 765 * Handle REMOVE_INITIATOR request: Removes an initiator entry. 766 * 767 * Parameter: 768 * par The request parameter containing the ID. 769 * 770 * Returns: status 771 */ 772 773 uint32_t 774 remove_initiator_portal(iscsid_sym_id_t * par) 775 { 776 initiator_t *init; 777 778 if ((init = find_initiator(par)) == NULL) 779 return ISCSID_STATUS_INVALID_INITIATOR_ID; 780 781 LOCK_SESSIONS; 782 list[INITIATOR_LIST].num_entries--; 783 784 TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link); 785 UNLOCK_SESSIONS; 786 787 free(init); 788 789 return ISCSID_STATUS_SUCCESS; 790 } 791 792 793 794 /* 795 * get_initiator_portal: 796 * Handle GET_INITIATOR_PORTAL request: Return information about the given 797 * initiator portal. 798 * 799 * Parameter: 800 * par The request parameters. 801 * prsp Pointer to address of response buffer. 802 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 803 * for static buffer. 804 */ 805 806 void 807 get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp, 808 int *prsp_temp) 809 { 810 iscsid_get_initiator_rsp_t *res; 811 iscsid_response_t *rsp = *prsp; 812 initiator_t *init; 813 814 DEB(10, ("get_initiator_portal, id %d (%s)\n", par->id, par->name)); 815 816 if ((init = find_initiator(par)) == NULL) { 817 rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID; 818 return; 819 } 820 821 rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp); 822 if (rsp == NULL) 823 return; 824 825 res = (iscsid_get_initiator_rsp_t *)(void *)rsp->parameter; 826 res->portal_id = init->entry.sid; 827 strlcpy((char *)res->address, (char *)init->address, sizeof(res->address)); 828 } 829 830 831 /* 832 * select_initiator: 833 * Select the initiator portal to use. 834 * Selects the portal with the least number of active connections. 835 * 836 * Returns: 837 * Pointer to the portal, NULL if no portals are defined. 838 * 839 * NOTE: Called with session list locked, so don't lock again. 840 */ 841 842 initiator_t * 843 select_initiator(void) 844 { 845 generic_entry_t *curr; 846 initiator_t *imin = NULL; 847 uint32_t ccnt = 64 * 1024; /* probably not more than 64k connections... */ 848 849 if (!list[INITIATOR_LIST].num_entries) 850 return NULL; 851 852 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 853 initiator_t *i = (void *)curr; 854 if ((i->active_connections < ccnt)) { 855 ccnt = i->active_connections; 856 imin = i; 857 } 858 } 859 return imin; 860 } 861 862 /* ------------------------------------------------------------------------- */ 863 864 /* 865 * event_kill_session: 866 * Handle SESSION_TERMINATED event: Remove session and all associated 867 * connections. 868 * 869 * Parameter: 870 * sid Session ID 871 */ 872 873 void 874 event_kill_session(uint32_t sid) 875 { 876 session_t *sess; 877 connection_t *conn; 878 portal_t *portal; 879 initiator_t *init; 880 881 LOCK_SESSIONS; 882 883 sess = find_session_id(sid); 884 885 if (sess == NULL) { 886 UNLOCK_SESSIONS; 887 return; 888 } 889 890 TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link); 891 list[SESSION_LIST].num_entries--; 892 893 UNLOCK_SESSIONS; 894 895 while ((conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections)) != NULL) { 896 TAILQ_REMOVE(&sess->connections, &conn->entry, link); 897 898 portal = find_portal_id(conn->portal.sid.id); 899 if (portal != NULL) 900 portal->active_connections--; 901 902 init = find_initiator_id(conn->initiator_id); 903 if (init != NULL) 904 init->active_connections--; 905 906 free(conn); 907 } 908 free(sess); 909 } 910 911 912 /* 913 * event_kill_connection: 914 * Handle CONNECTION_TERMINATED event: Remove connection from session. 915 * 916 * Parameter: 917 * sid Session ID 918 * cid Connection ID 919 */ 920 921 void 922 event_kill_connection(uint32_t sid, uint32_t cid) 923 { 924 session_t *sess; 925 connection_t *conn; 926 portal_t *portal; 927 initiator_t *init; 928 929 LOCK_SESSIONS; 930 931 sess = find_session_id(sid); 932 if (sess == NULL) { 933 UNLOCK_SESSIONS; 934 return; 935 } 936 937 conn = find_connection_id(sess, cid); 938 if (conn == NULL) { 939 UNLOCK_SESSIONS; 940 return; 941 } 942 943 TAILQ_REMOVE(&sess->connections, &conn->entry, link); 944 sess->num_connections--; 945 946 init = find_initiator_id(conn->initiator_id); 947 if (init != NULL) 948 init->active_connections--; 949 950 UNLOCK_SESSIONS; 951 952 portal = find_portal_id(conn->portal.sid.id); 953 if (portal != NULL) 954 portal->active_connections--; 955 956 free(conn); 957 } 958