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