1 /* $NetBSD: iscsid_lists.c,v 1.8 2012/12/29 08:28:20 mlelstv 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 #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 49 static void 50 verify_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 79 void 80 verify_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 103 generic_entry_t * 104 find_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 127 generic_entry_t * 128 find_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 152 generic_entry_t * 153 find_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 172 uint32_t 173 get_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 194 target_t * 195 find_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 220 target_t * 221 find_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 250 portal_t * 251 find_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 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 /* 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 314 void 315 get_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 376 void 377 search_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 505 void 506 get_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->num_connections = sess->num_connections; 547 if (conn) { 548 ent->first_connection_id = conn->entry.sid.id; 549 ent->portal_id = conn->portal.sid.id; 550 ent->initiator_id = conn->initiator_id; 551 } else { 552 ent->first_connection_id = 0; 553 ent->portal_id = 0; 554 ent->initiator_id = 0; 555 } 556 ent++; 557 } 558 UNLOCK_SESSIONS; 559 } 560 561 /* 562 * get_connection_list: 563 * Handle GET_CONNECTION_LIST request: Return a list of connections 564 * for a session. 565 * 566 * Parameter: 567 * prsp Pointer to address of response buffer. 568 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 569 * for static buffer. 570 */ 571 572 void 573 get_connection_list(iscsid_sym_id_t *req, iscsid_response_t **prsp, 574 int *prsp_temp) 575 { 576 iscsid_get_connection_list_rsp_t *res; 577 iscsid_response_t *rsp = *prsp; 578 iscsid_connection_list_entry_t *ent; 579 generic_entry_t *curr; 580 session_t *sess; 581 connection_t *conn; 582 int num; 583 584 DEB(10, ("get_connection_list\n")); 585 586 LOCK_SESSIONS; 587 if ((sess = find_session(req)) == NULL) { 588 UNLOCK_SESSIONS; 589 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 590 return; 591 } 592 593 num = sess->num_connections; 594 rsp = make_rsp(sizeof(iscsid_get_connection_list_rsp_t) + 595 (num - 1) * sizeof(iscsid_connection_list_entry_t), 596 prsp, prsp_temp); 597 if (rsp == NULL) { 598 UNLOCK_SESSIONS; 599 return; 600 } 601 /* copy the ID of all list entries */ 602 res = (iscsid_get_connection_list_rsp_t *)(void *)rsp->parameter; 603 res->num_connections = num; 604 ent = res->connection; 605 606 TAILQ_FOREACH(curr, &sess->connections, link) { 607 conn = (connection_t *)(void *)curr; 608 ent->connection_id = conn->entry.sid; 609 ent->target_portal_id = conn->portal.sid; 610 ent->target_portal = conn->portal.addr; 611 ent++; 612 } 613 UNLOCK_SESSIONS; 614 } 615 616 617 /* 618 * get_connection_info: 619 * Handle GET_CONNECTION_INFO request: Return information about a connection 620 * 621 * Parameter: 622 * par The request parameters. 623 * prsp Pointer to address of response buffer. 624 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 625 * for static buffer. 626 */ 627 628 void 629 get_connection_info(iscsid_get_connection_info_req_t * req, 630 iscsid_response_t ** prsp, int *prsp_temp) 631 { 632 iscsid_get_connection_info_rsp_t *res; 633 iscsid_response_t *rsp = *prsp; 634 session_t *sess; 635 connection_t *conn; 636 initiator_t *init = NULL; 637 638 DEB(10, ("get_connection_info, session %d, connection %d\n", 639 req->session_id.id, req->connection_id.id)); 640 641 LOCK_SESSIONS; 642 if ((sess = find_session(&req->session_id)) == NULL) { 643 UNLOCK_SESSIONS; 644 rsp->status = ISCSID_STATUS_INVALID_SESSION_ID; 645 return; 646 } 647 if (!req->connection_id.id && !req->connection_id.name[0]) { 648 conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections); 649 } else if ((conn = find_connection(sess, &req->connection_id)) == NULL) { 650 UNLOCK_SESSIONS; 651 rsp->status = ISCSID_STATUS_INVALID_CONNECTION_ID; 652 return; 653 } 654 655 rsp = make_rsp(sizeof(iscsid_get_connection_info_rsp_t), prsp, prsp_temp); 656 if (rsp == NULL) { 657 UNLOCK_SESSIONS; 658 return; 659 } 660 661 if (conn && conn->initiator_id) 662 init = find_initiator_id(conn->initiator_id); 663 664 res = (iscsid_get_connection_info_rsp_t *)(void *)rsp->parameter; 665 666 res->session_id = sess->entry.sid; 667 if (conn) { 668 res->connection_id = conn->entry.sid; 669 res->target_portal_id = conn->portal.sid; 670 res->target_portal = conn->portal.addr; 671 strlcpy((char *)res->TargetName, (char *)conn->target.TargetName, 672 sizeof(res->TargetName)); 673 strlcpy((char *)res->TargetAlias, (char *)conn->target.TargetAlias, 674 sizeof(res->TargetAlias)); 675 } else { 676 res->connection_id.id = 0; 677 res->connection_id.name[0] = '\0'; 678 res->target_portal_id.id = 0; 679 res->target_portal_id.name[0] = '\0'; 680 memset(&res->target_portal, 0, sizeof(res->target_portal)); 681 memset(&res->TargetName, 0, sizeof(res->TargetName)); 682 memset(&res->TargetAlias, 0, sizeof(res->TargetAlias)); 683 } 684 if (init != NULL) { 685 res->initiator_id = init->entry.sid; 686 strlcpy((char *)res->initiator_address, (char *)init->address, 687 sizeof(res->initiator_address)); 688 } 689 UNLOCK_SESSIONS; 690 } 691 692 /* ------------------------------------------------------------------------- */ 693 694 /* 695 * find_initator_by_addr: 696 * Find an Initiator Portal by Address. 697 * 698 * Parameter: the address 699 * 700 * Returns: The pointer to the portal (or NULL if not found) 701 */ 702 703 static initiator_t * 704 find_initiator_by_addr(uint8_t * addr) 705 { 706 generic_entry_t *curr; 707 initiator_t *i = NULL; 708 709 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 710 i = (void *)curr; 711 if (strcmp((char *)i->address, (char *)addr) == 0) 712 break; 713 } 714 715 /* return curr instead of i because if not found, curr==NULL */ 716 DEB(9, ("Find_initiator_by_addr returns %p\n", curr)); 717 return (initiator_t *)curr; 718 } 719 720 721 /* 722 * add_initiator_portal: 723 * Add an initiator portal. 724 * 725 * Parameter: 726 * par The request parameters. 727 * prsp Pointer to address of response buffer. 728 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 729 * for static buffer. 730 */ 731 732 void 733 add_initiator_portal(iscsid_add_initiator_req_t *par, iscsid_response_t **prsp, 734 int *prsp_temp) 735 { 736 iscsid_add_initiator_rsp_t *res; 737 iscsid_response_t *rsp = *prsp; 738 initiator_t *init; 739 740 DEB(9, ("AddInitiatorPortal '%s' (name '%s')\n", par->address, par->name)); 741 742 if (find_initiator_by_addr(par->address) != NULL) { 743 rsp->status = ISCSID_STATUS_DUPLICATE_ENTRY; 744 return; 745 } 746 747 if (find_initiator_name(par->name) != NULL) { 748 rsp->status = ISCSID_STATUS_DUPLICATE_NAME; 749 return; 750 } 751 752 if ((init = calloc(1, sizeof(*init))) == NULL) { 753 rsp->status = ISCSID_STATUS_NO_RESOURCES; 754 return; 755 } 756 757 DEB(9, ("AddInitiatorPortal initiator_id = %d\n", initiator_id)); 758 759 for (initiator_id++; 760 !initiator_id || find_initiator_id(initiator_id) != NULL;) 761 initiator_id++; 762 763 init->entry.sid.id = initiator_id; 764 strlcpy((char *)init->entry.sid.name, (char *)par->name, sizeof(init->entry.sid.name)); 765 strlcpy((char *)init->address, (char *)par->address, sizeof(init->address)); 766 767 rsp = make_rsp(sizeof(iscsid_add_initiator_rsp_t), prsp, prsp_temp); 768 if (rsp == NULL) 769 return; 770 771 LOCK_SESSIONS; 772 TAILQ_INSERT_TAIL(&list[INITIATOR_LIST].list, &init->entry, link); 773 list[INITIATOR_LIST].num_entries++; 774 UNLOCK_SESSIONS; 775 776 res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter; 777 res->portal_id = init->entry.sid.id; 778 } 779 780 781 /* 782 * remove_initiator_portal: 783 * Handle REMOVE_INITIATOR request: Removes an initiator entry. 784 * 785 * Parameter: 786 * par The request parameter containing the ID. 787 * 788 * Returns: status 789 */ 790 791 uint32_t 792 remove_initiator_portal(iscsid_sym_id_t * par) 793 { 794 initiator_t *init; 795 796 if ((init = find_initiator(par)) == NULL) 797 return ISCSID_STATUS_INVALID_INITIATOR_ID; 798 799 LOCK_SESSIONS; 800 list[INITIATOR_LIST].num_entries--; 801 802 TAILQ_REMOVE(&list[INITIATOR_LIST].list, &init->entry, link); 803 UNLOCK_SESSIONS; 804 805 free(init); 806 807 return ISCSID_STATUS_SUCCESS; 808 } 809 810 811 812 /* 813 * get_initiator_portal: 814 * Handle GET_INITIATOR_PORTAL request: Return information about the given 815 * initiator portal. 816 * 817 * Parameter: 818 * par The request parameters. 819 * prsp Pointer to address of response buffer. 820 * prsp_temp Will be set to TRUE if buffer was allocated, FALSE 821 * for static buffer. 822 */ 823 824 void 825 get_initiator_portal(iscsid_sym_id_t *par, iscsid_response_t **prsp, 826 int *prsp_temp) 827 { 828 iscsid_get_initiator_rsp_t *res; 829 iscsid_response_t *rsp = *prsp; 830 initiator_t *init; 831 832 DEB(10, ("get_initiator_portal, id %d (%s)\n", par->id, par->name)); 833 834 if ((init = find_initiator(par)) == NULL) { 835 rsp->status = ISCSID_STATUS_INVALID_INITIATOR_ID; 836 return; 837 } 838 839 rsp = make_rsp(sizeof(iscsid_get_initiator_rsp_t), prsp, prsp_temp); 840 if (rsp == NULL) 841 return; 842 843 res = (iscsid_get_initiator_rsp_t *)(void *)rsp->parameter; 844 res->portal_id = init->entry.sid; 845 strlcpy((char *)res->address, (char *)init->address, sizeof(res->address)); 846 } 847 848 849 /* 850 * select_initiator: 851 * Select the initiator portal to use. 852 * Selects the portal with the least number of active connections. 853 * 854 * Returns: 855 * Pointer to the portal, NULL if no portals are defined. 856 * 857 * NOTE: Called with session list locked, so don't lock again. 858 */ 859 860 initiator_t * 861 select_initiator(void) 862 { 863 generic_entry_t *curr; 864 initiator_t *imin = NULL; 865 uint32_t ccnt = 64 * 1024; /* probably not more than 64k connections... */ 866 867 if (!list[INITIATOR_LIST].num_entries) 868 return NULL; 869 870 TAILQ_FOREACH(curr, &list[INITIATOR_LIST].list, link) { 871 initiator_t *i = (void *)curr; 872 if ((i->active_connections < ccnt)) { 873 ccnt = i->active_connections; 874 imin = i; 875 } 876 } 877 return imin; 878 } 879 880 /* ------------------------------------------------------------------------- */ 881 882 /* 883 * event_kill_session: 884 * Handle SESSION_TERMINATED event: Remove session and all associated 885 * connections. 886 * 887 * Parameter: 888 * sid Session ID 889 */ 890 891 void 892 event_kill_session(uint32_t sid) 893 { 894 session_t *sess; 895 connection_t *conn; 896 portal_t *portal; 897 initiator_t *init; 898 899 LOCK_SESSIONS; 900 901 sess = find_session_id(sid); 902 903 if (sess == NULL) { 904 UNLOCK_SESSIONS; 905 return; 906 } 907 908 TAILQ_REMOVE(&list[SESSION_LIST].list, &sess->entry, link); 909 list[SESSION_LIST].num_entries--; 910 911 UNLOCK_SESSIONS; 912 913 while ((conn = (connection_t *)(void *)TAILQ_FIRST(&sess->connections)) != NULL) { 914 TAILQ_REMOVE(&sess->connections, &conn->entry, link); 915 916 portal = find_portal_id(conn->portal.sid.id); 917 if (portal != NULL) 918 portal->active_connections--; 919 920 init = find_initiator_id(conn->initiator_id); 921 if (init != NULL) 922 init->active_connections--; 923 924 free(conn); 925 } 926 free(sess); 927 } 928 929 930 /* 931 * event_kill_connection: 932 * Handle CONNECTION_TERMINATED event: Remove connection from session. 933 * 934 * Parameter: 935 * sid Session ID 936 * cid Connection ID 937 */ 938 939 void 940 event_kill_connection(uint32_t sid, uint32_t cid) 941 { 942 session_t *sess; 943 connection_t *conn; 944 portal_t *portal; 945 initiator_t *init; 946 947 LOCK_SESSIONS; 948 949 sess = find_session_id(sid); 950 if (sess == NULL) { 951 UNLOCK_SESSIONS; 952 return; 953 } 954 955 conn = find_connection_id(sess, cid); 956 if (conn == NULL) { 957 UNLOCK_SESSIONS; 958 return; 959 } 960 961 TAILQ_REMOVE(&sess->connections, &conn->entry, link); 962 sess->num_connections--; 963 964 init = find_initiator_id(conn->initiator_id); 965 if (init != NULL) 966 init->active_connections--; 967 968 UNLOCK_SESSIONS; 969 970 portal = find_portal_id(conn->portal.sid.id); 971 if (portal != NULL) 972 portal->active_connections--; 973 974 free(conn); 975 } 976