1/* $NetBSD: iscsid_driverif.c,v 1.10 2023/12/27 18:07:30 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#include "iscsid_globals.h" 32 33#include <sys/socket.h> 34#include <netinet/in.h> 35#include <netinet/tcp.h> 36#include <netdb.h> 37 38 39/* Global node name (Initiator Name and Alias) */ 40iscsid_set_node_name_req_t node_name; 41 42/* -------------------------------------------------------------------------- */ 43 44/* 45 * set_node_name: 46 * Handle set_node_name request. Copy names into our own buffers and 47 * set the driver's info as well. 48 * 49 * Parameter: 50 * par The request parameter 51 * 52 * Returns: Status. 53 */ 54 55uint32_t 56set_node_name(iscsid_set_node_name_req_t * par) 57{ 58 iscsi_set_node_name_parameters_t snp; 59 60 (void) memset(&snp, 0x0, sizeof(snp)); 61 if (!par->InitiatorName[0]) 62 return ISCSID_STATUS_NO_INITIATOR_NAME; 63 64 if (strlen((char *)par->InitiatorName) > ISCSI_STRING_LENGTH 65 || strlen((char *)par->InitiatorAlias) > ISCSI_STRING_LENGTH) 66 return ISCSID_STATUS_PARAMETER_INVALID; 67 68 if (!par->InitiatorAlias[0]) 69 gethostname((char *)node_name.InitiatorAlias, sizeof(node_name.InitiatorAlias)); 70 71 node_name = *par; 72 73 strlcpy((char *)snp.InitiatorName, (char *)par->InitiatorName, 74 sizeof(snp.InitiatorName)); 75 strlcpy((char *)snp.InitiatorAlias, (char *)par->InitiatorAlias, 76 sizeof(snp.InitiatorAlias)); 77 memcpy(snp.ISID, par->ISID, 6); 78 79 DEB(10, ("Setting Node Name: %s (%s)", 80 snp.InitiatorName, snp.InitiatorAlias)); 81 (void)ioctl(driver, ISCSI_SET_NODE_NAME, &snp); 82 return snp.status; 83} 84 85 86/* 87 * bind_socket: 88 * Bind socket to initiator portal. 89 * 90 * Parameter: 91 * sock The socket 92 * addr The initiator portal address 93 * 94 * Returns: 95 * TRUE on success, FALSE on error. 96 */ 97 98static int 99bind_socket(int sock, uint8_t * addr) 100{ 101 struct addrinfo hints, *ai, *ai0; 102 int ret = FALSE; 103 104 DEB(8, ("Binding to <%s>", addr)); 105 106 memset(&hints, 0, sizeof(hints)); 107 hints.ai_family = AF_UNSPEC; 108 hints.ai_socktype = SOCK_STREAM; 109 hints.ai_flags = AI_PASSIVE; 110 if (getaddrinfo((char *)addr, NULL, &hints, &ai0)) 111 return ret; 112 113 for (ai = ai0; ai; ai = ai->ai_next) { 114 if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) 115 continue; 116 117 listen(sock, 5); 118 ret = TRUE; 119 break; 120 } 121 freeaddrinfo(ai0); 122 123 return ret; 124} 125 126 127/* -------------------------------------------------------------------------- */ 128 129/* 130 * find_free_portal: 131 * Find the Portal with the least number of connections. 132 * 133 * Parameter: the portal group 134 * 135 * Returns: The pointer to the first free portal (or NULL if none found) 136 */ 137 138static portal_t * 139find_free_portal(portal_group_t * group) 140{ 141 portal_t *curr, *m; 142 uint32_t n; 143 144 if ((curr = TAILQ_FIRST(&group->portals)) == NULL) 145 return NULL; 146 147 m = curr; 148 n = curr->active_connections; 149 150 while ((curr = TAILQ_NEXT(curr, group_list)) != NULL) 151 if (curr->active_connections < n) { 152 m = curr; 153 n = curr->active_connections; 154 } 155 156 return m; 157} 158 159 160/* 161 * make_connection: 162 * Common routine for login and add_connection. Creates the connection 163 * structure, connects the socket, and executes the login. 164 * 165 * Parameter: 166 * sess The associated session. NULL for a send_targets request. 167 * req The request parameters. NULL for send_targets. 168 * res The response buffer. For SendTargets, only the status 169 * is set. For a "real" login, the login response 170 * is filled in. 171 * stid Send target request only, else NULL. Pointer to uint32: 172 * On Input, contains send target ID 173 * On Output, receives session ID 174 * 175 * Returns: The connection structure on successful login, else NULL. 176 * 177 * NOTE: Session list must be locked on entry. 178 */ 179 180static connection_t * 181make_connection(session_t * sess, iscsid_login_req_t * req, 182 iscsid_response_t * res, uint32_t * stid) 183{ 184 connection_t *conn; 185 iscsi_login_parameters_t loginp; 186 int sock; 187 int ret; 188 int yes = 1; 189 target_t *target; 190 portal_t *portal = NULL; 191 iscsi_portal_address_t *addr; 192 struct addrinfo hints, *ai, *ai0; 193 char portnum[6]; 194 initiator_t *init; 195 196 DEB(9, ("Make Connection sess=%p, req=%p, res=%p, stid=%p", 197 sess, req, res, stid)); 198 (void) memset(&loginp, 0x0, sizeof(loginp)); 199 200 /* find the target portal */ 201 if (stid != NULL) { 202 send_target_t *starget; 203 204 if ((starget = find_send_target_id(*stid)) == NULL) { 205 res->status = ISCSID_STATUS_INVALID_TARGET_ID; 206 return NULL; 207 } 208 addr = &starget->addr; 209 target = (target_t *)(void *)starget; 210 } else { 211 if (NO_ID(&req->portal_id) 212 || (portal = find_portal(&req->portal_id)) == NULL) { 213 portal_group_t *group; 214 215 /* if no ID was specified, use target from existing session */ 216 if (NO_ID(&req->portal_id)) { 217 if (!sess->num_connections || 218 ((target = find_target_id(TARGET_LIST, 219 sess->target.sid.id)) == NULL)) { 220 res->status = ISCSID_STATUS_INVALID_PORTAL_ID; 221 return NULL; 222 } 223 } 224 /* if a target was given instead, use it */ 225 else if ((target = 226 find_target(TARGET_LIST, &req->portal_id)) == NULL) { 227 res->status = ISCSID_STATUS_INVALID_PORTAL_ID; 228 return NULL; 229 } 230 /* now get from target to portal - if this is the first connection, */ 231 /* just use the first portal group. */ 232 if (!sess->num_connections) { 233 group = TAILQ_FIRST(&target->group_list); 234 } 235 /* if it's a second connection, use an available portal in the same */ 236 /* portal group */ 237 else { 238 conn = (connection_t *)(void *) 239 TAILQ_FIRST(&sess->connections); 240 241 if (conn == NULL || 242 (portal = find_portal_id(conn->portal.sid.id)) == NULL) { 243 res->status = ISCSID_STATUS_INVALID_PORTAL_ID; 244 return NULL; 245 } 246 group = portal->group; 247 } 248 249 if ((portal = find_free_portal(group)) == NULL) { 250 res->status = ISCSID_STATUS_INVALID_PORTAL_ID; 251 return NULL; 252 } 253 DEB(1, ("find_free_portal returns pid=%d", portal->entry.sid.id)); 254 } else 255 target = portal->target; 256 257 addr = &portal->addr; 258 259 /* symbolic name for connection? check for duplicates */ 260 if (req->sym_name[0]) { 261 void *p; 262 263 if (sess->num_connections) 264 p = find_connection_name(sess, req->sym_name); 265 else 266 p = find_session_name(req->sym_name); 267 if (p) { 268 res->status = ISCSID_STATUS_DUPLICATE_NAME; 269 return NULL; 270 } 271 } 272 } 273 274 if (req != NULL && !NO_ID(&req->initiator_id)) { 275 if ((init = find_initiator(&req->initiator_id)) == NULL) { 276 res->status = ISCSID_STATUS_INVALID_INITIATOR_ID; 277 return NULL; 278 } 279 } else 280 init = select_initiator(); 281 282 /* translate target address */ 283 DEB(8, ("Connecting to <%s>, port %d", addr->address, addr->port)); 284 285 memset(&hints, 0, sizeof(hints)); 286 hints.ai_family = AF_UNSPEC; 287 hints.ai_socktype = SOCK_STREAM; 288 snprintf(portnum, sizeof(portnum), "%u", addr->port 289 ? addr->port : ISCSI_DEFAULT_PORT); 290 ret = getaddrinfo((char *)addr->address, portnum, &hints, &ai0); 291 switch (ret) { 292 case 0: 293 break; 294 case EAI_NODATA: 295 res->status = ISCSID_STATUS_HOST_NOT_FOUND; 296 break; 297 case EAI_AGAIN: 298 res->status = ISCSID_STATUS_HOST_TRY_AGAIN; 299 break; 300 default: 301 res->status = ISCSID_STATUS_HOST_ERROR; 302 break; 303 } 304 305 /* alloc the connection structure */ 306 conn = calloc(1, sizeof(*conn)); 307 if (conn == NULL) { 308 freeaddrinfo(ai0); 309 res->status = ISCSID_STATUS_NO_RESOURCES; 310 return NULL; 311 } 312 313 res->status = ISCSID_STATUS_HOST_ERROR; 314 sock = -1; 315 for (ai = ai0; ai; ai = ai->ai_next) { 316 /* create and connect the socket */ 317 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 318 if (sock < 0) { 319 res->status = ISCSID_STATUS_SOCKET_ERROR; 320 break; 321 } 322 323 if (init) { 324 if (!bind_socket(sock, init->address)) { 325 close(sock); 326 res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR; 327 break; 328 } 329 } 330 331 DEB(8, ("Connecting socket")); 332 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 333 close(sock); 334 res->status = ISCSID_STATUS_CONNECT_ERROR; 335 continue; 336 } 337 338 res->status = ISCSID_STATUS_SUCCESS; 339 break; 340 } 341 freeaddrinfo(ai0); 342 343 if (sock < 0) { 344 free(conn); 345 DEB(1, ("Connecting to socket failed (error %d), returning %d", 346 errno, res->status)); 347 return NULL; 348 } 349 350 /* speed up socket processing */ 351 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes)); 352 /* setup login parameter structure */ 353 loginp.socket = sock; 354 if (target->TargetName[0]) { 355 loginp.is_present.TargetName = 1; 356 loginp.TargetName = target->TargetName; 357 } 358 if (target->options.is_present.MaxConnections) { 359 loginp.is_present.MaxConnections = 1; 360 loginp.MaxConnections = target->options.MaxConnections; 361 } 362 if (target->options.is_present.DataDigest) { 363 loginp.is_present.DataDigest = 1; 364 loginp.DataDigest = target->options.DataDigest; 365 } 366 if (target->options.is_present.HeaderDigest) { 367 loginp.is_present.HeaderDigest = 1; 368 loginp.HeaderDigest = target->options.HeaderDigest; 369 } 370 if (target->options.is_present.DefaultTime2Retain) { 371 loginp.is_present.DefaultTime2Retain = 1; 372 loginp.DefaultTime2Retain = target->options.DefaultTime2Retain; 373 } 374 if (target->options.is_present.DefaultTime2Wait) { 375 loginp.is_present.DefaultTime2Wait = 1; 376 loginp.DefaultTime2Wait = target->options.DefaultTime2Wait; 377 } 378 if (target->options.is_present.ErrorRecoveryLevel) { 379 loginp.is_present.ErrorRecoveryLevel = 1; 380 loginp.ErrorRecoveryLevel = target->options.ErrorRecoveryLevel; 381 } 382 if (target->options.is_present.MaxRecvDataSegmentLength) { 383 loginp.is_present.MaxRecvDataSegmentLength = 1; 384 loginp.MaxRecvDataSegmentLength = 385 target->options.MaxRecvDataSegmentLength; 386 } 387 if (target->auth.auth_info.auth_number) { 388 loginp.is_present.auth_info = 1; 389 loginp.auth_info = target->auth.auth_info; 390 if (target->auth.password[0]) { 391 loginp.is_present.password = 1; 392 loginp.password = target->auth.password; 393 } 394 if (target->auth.target_password[0]) { 395 loginp.is_present.target_password = 1; 396 loginp.target_password = target->auth.target_password; 397 } 398 if (target->auth.user_name[0]) { 399 loginp.is_present.user_name = 1; 400 loginp.user_name = target->auth.user_name; 401 } 402 } 403 loginp.is_present.TargetAlias = 1; 404 loginp.TargetAlias = target->TargetAlias; 405 406 if (portal != NULL) { 407 /* override general target options with portal options (if specified) */ 408 if (portal->options.is_present.DataDigest) { 409 loginp.is_present.DataDigest = 1; 410 loginp.DataDigest = portal->options.DataDigest; 411 } 412 if (portal->options.is_present.HeaderDigest) { 413 loginp.is_present.HeaderDigest = 1; 414 loginp.HeaderDigest = portal->options.HeaderDigest; 415 } 416 if (portal->options.is_present.MaxRecvDataSegmentLength) { 417 loginp.is_present.MaxRecvDataSegmentLength = 1; 418 loginp.MaxRecvDataSegmentLength = 419 portal->options.MaxRecvDataSegmentLength; 420 } 421 } 422 423 if (req != NULL) { 424 loginp.session_id = get_id(&list[SESSION_LIST].list, &req->session_id); 425 loginp.login_type = req->login_type; 426 } else 427 loginp.login_type = ISCSI_LOGINTYPE_DISCOVERY; 428 429 DEB(5, ("Calling Login...")); 430 431 ret = ioctl(driver, (sess != NULL && sess->num_connections) 432 ? ISCSI_ADD_CONNECTION : ISCSI_LOGIN, &loginp); 433 434 res->status = loginp.status; 435 436 if (ret) 437 close(sock); 438 439 if (ret || loginp.status) { 440 free(conn); 441 if (!res->status) 442 res->status = ISCSID_STATUS_GENERAL_ERROR; 443 return NULL; 444 } 445 /* connection established! link connection into session and return IDs */ 446 447 conn->loginp = loginp; 448 conn->entry.sid.id = loginp.connection_id; 449 if (req != NULL) { 450 strlcpy((char *)conn->entry.sid.name, (char *)req->sym_name, 451 sizeof(conn->entry.sid.name)); 452 } 453 454 /* 455 Copy important target information 456 */ 457 conn->target.sid = target->entry.sid; 458 strlcpy((char *)conn->target.TargetName, (char *)target->TargetName, 459 sizeof(conn->target.TargetName)); 460 strlcpy((char *)conn->target.TargetAlias, (char *)target->TargetAlias, 461 sizeof(conn->target.TargetAlias)); 462 conn->target.options = target->options; 463 conn->target.auth = target->auth; 464 conn->portal.addr = *addr; 465 466 conn->session = sess; 467 468 if (stid == NULL) { 469 iscsid_login_rsp_t *rsp = (iscsid_login_rsp_t *)(void *) 470 res->parameter; 471 472 sess->entry.sid.id = loginp.session_id; 473 TAILQ_INSERT_TAIL(&sess->connections, &conn->entry, link); 474 sess->num_connections++; 475 476 res->parameter_length = sizeof(*rsp); 477 rsp->connection_id = conn->entry.sid; 478 rsp->session_id = sess->entry.sid; 479 480 if (init != NULL) { 481 conn->initiator_id = init->entry.sid.id; 482 init->active_connections++; 483 } 484 } else 485 *stid = loginp.session_id; 486 487 /* 488 Copy important portal information 489 */ 490 if (portal != NULL) { 491 conn->portal.sid = portal->entry.sid; 492 portal->active_connections++; 493 } 494 495 return conn; 496} 497 498 499/* 500 * event_recover_connection: 501 * Handle RECOVER_CONNECTION event: Attempt to re-establish connection. 502 * 503 * Parameter: 504 * sid Session ID 505 * cid Connection ID 506 */ 507 508static void 509event_recover_connection(uint32_t sid, uint32_t cid) 510{ 511 int sock, ret; 512 int yes = 1; 513 session_t *sess; 514 connection_t *conn; 515 portal_t *portal; 516 initiator_t *init; 517 iscsi_portal_address_t *addr; 518 struct addrinfo hints, *ai, *ai0; 519 char portnum[6]; 520 521 DEB(1, ("Event_Recover_Connection sid=%d, cid=%d", sid, cid)); 522 523 LOCK_SESSIONS; 524 525 sess = find_session_id(sid); 526 if (sess == NULL) { 527 UNLOCK_SESSIONS; 528 return; 529 } 530 531 conn = find_connection_id(sess, cid); 532 if (conn == NULL) { 533 UNLOCK_SESSIONS; 534 return; 535 } 536 537 UNLOCK_SESSIONS; 538 539 conn->loginp.status = ISCSI_STATUS_CONNECTION_FAILED; 540 541 /* If we can't find the portal to connect to, abort. */ 542 543 if ((portal = find_portal_id(conn->portal.sid.id)) == NULL) 544 return; 545 546 init = find_initiator_id(conn->initiator_id); 547 addr = &portal->addr; 548 conn->portal.addr = *addr; 549 550 /* translate target address */ 551 DEB(1, ("Event_Recover_Connection Connecting to <%s>, port %d", 552 addr->address, addr->port)); 553 554 memset(&hints, 0, sizeof(hints)); 555 hints.ai_family = AF_UNSPEC; 556 hints.ai_socktype = SOCK_STREAM; 557 snprintf(portnum, sizeof(portnum), "%u", addr->port 558 ? addr->port : ISCSI_DEFAULT_PORT); 559 ret = getaddrinfo((char *)addr->address, portnum, &hints, &ai0); 560 if (ret) { 561 DEB(1, ("getaddrinfo failed (%s)", gai_strerror(ret))); 562 return; 563 } 564 565 sock = -1; 566 for (ai = ai0; ai; ai = ai->ai_next) { 567 568 /* create and connect the socket */ 569 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); 570 if (sock < 0) { 571 DEB(1, ("Creating socket failed (error %d)", errno)); 572 break; 573 } 574 575 DEB(1, ("recover_connection: Socket = %d", sock)); 576 577 if (init) { 578 if (!bind_socket(sock, init->address)) { 579 DEB(1, ("Binding to interface failed (error %d)", errno)); 580 close(sock); 581 sock = -1; 582 continue; 583 } 584 } 585 586 if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) { 587 close(sock); 588 sock = -1; 589 DEB(1, ("Connecting to socket failed (error %d)", errno)); 590 continue; 591 } 592 593 break; 594 } 595 freeaddrinfo(ai0); 596 597 if (sock < 0) 598 return; 599 600 /* speed up socket processing */ 601 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes)); 602 conn->loginp.socket = sock; 603 conn->loginp.status = 0; 604 ret = ioctl(driver, ISCSI_RESTORE_CONNECTION, &conn->loginp); 605 606 if (ret) 607 close(sock); 608} 609 610 611/* 612 * login: 613 * Handle LOGIN request: Log into given portal. Create session, then 614 * let make_connection do the rest. 615 * 616 * Parameter: 617 * req The request parameters 618 * res The response buffer 619 */ 620 621void 622log_in(iscsid_login_req_t * req, iscsid_response_t * res) 623{ 624 session_t *sess; 625 connection_t *conn; 626 627 sess = calloc(1, sizeof(*sess)); 628 if (sess == NULL) { 629 res->status = ISCSID_STATUS_NO_RESOURCES; 630 return; 631 } 632 TAILQ_INIT(&sess->connections); 633 strlcpy((char *)sess->entry.sid.name, (char *)req->sym_name, 634 sizeof(sess->entry.sid.name)); 635 636 LOCK_SESSIONS; 637 conn = make_connection(sess, req, res, 0); 638 639 if (conn == NULL) 640 free(sess); 641 else { 642 sess->target = conn->target; 643 TAILQ_INSERT_TAIL(&list[SESSION_LIST].list, &sess->entry, link); 644 list[SESSION_LIST].num_entries++; 645 } 646 UNLOCK_SESSIONS; 647} 648 649/* 650 * add_connection: 651 * Handle ADD_CONNECTION request: Log secondary connection into given portal. 652 * Find the session, then let make_connection do the rest. 653 * 654 * Parameter: 655 * req The request parameters 656 * res The response buffer 657 */ 658 659void 660add_connection(iscsid_login_req_t * req, iscsid_response_t * res) 661{ 662 session_t *sess; 663 664 LOCK_SESSIONS; 665 sess = find_session(&req->session_id); 666 if (sess == NULL) { 667 UNLOCK_SESSIONS; 668 res->status = ISCSID_STATUS_INVALID_SESSION_ID; 669 return; 670 } 671 672 make_connection(sess, req, res, 0); 673 UNLOCK_SESSIONS; 674} 675 676 677/* 678 * logout: 679 * Handle LOGOUT request: Log out the given session. 680 * 681 * Parameter: 682 * req The request parameters 683 * 684 * Returns: Response status 685 */ 686 687uint32_t 688log_out(iscsid_sym_id_t * req) 689{ 690 iscsi_logout_parameters_t logoutp; 691 session_t *sess; 692 int ret; 693 694 (void) memset(&logoutp, 0x0, sizeof(logoutp)); 695 LOCK_SESSIONS; 696 sess = find_session(req); 697 if (sess == NULL) { 698 UNLOCK_SESSIONS; 699 return ISCSID_STATUS_INVALID_SESSION_ID; 700 } 701 702 logoutp.session_id = sess->entry.sid.id; 703 UNLOCK_SESSIONS; 704 705 ret = ioctl(driver, ISCSI_LOGOUT, &logoutp); 706 DEB(9, ("Logout returns %d, status = %d", ret, logoutp.status)); 707 708 return logoutp.status; 709} 710 711 712/* 713 * remove_connection: 714 * Handle REMOVE_CONNECTION request: Log out the given connection. 715 * 716 * Parameter: 717 * req The request parameters 718 * 719 * Returns: Response status 720 */ 721 722uint32_t 723remove_connection(iscsid_remove_connection_req_t * req) 724{ 725 iscsi_remove_parameters_t removep; 726 session_t *sess; 727 connection_t *conn; 728 int ret; 729 730 LOCK_SESSIONS; 731 sess = find_session(&req->session_id); 732 if (sess == NULL) { 733 UNLOCK_SESSIONS; 734 return ISCSID_STATUS_INVALID_SESSION_ID; 735 } 736 conn = find_connection(sess, &req->connection_id); 737 if (conn == NULL) { 738 UNLOCK_SESSIONS; 739 return ISCSID_STATUS_INVALID_CONNECTION_ID; 740 } 741 742 removep.session_id = sess->entry.sid.id; 743 removep.connection_id = conn->entry.sid.id; 744 UNLOCK_SESSIONS; 745 746 ret = ioctl(driver, ISCSI_REMOVE_CONNECTION, &removep); 747 DEB(9, ("Remove Connection returns %d, status=%d", ret, removep.status)); 748 749 return removep.status; 750} 751 752/* 753 * send_targets: 754 * Handle SEND_TARGETS request: 755 * First login with type = discovery. 756 * Then send the SendTargets iSCSI request to the target, which will 757 * return a list of target portals. 758 * Then logout. 759 * 760 * Parameter: 761 * stid The send target ID 762 * response_buffer Pointer to pointer to buffer containing response 763 * The response contains the list of the target 764 * portals. The caller frees the buffer after it 765 * is done with it. 766 * response_size Pointer to variable which upon return will hold 767 * the size of the response buffer. 768 * 769 * Returns: Response status 770 */ 771 772uint32_t 773send_targets(uint32_t stid, uint8_t **response_buffer, uint32_t *response_size) 774{ 775 iscsi_send_targets_parameters_t sendt; 776 iscsi_logout_parameters_t logoutp; 777 int ret; 778 connection_t *conn; 779 iscsid_response_t res; 780 uint32_t rc = ISCSID_STATUS_SUCCESS; 781 782 (void) memset(&sendt, 0x0, sizeof(sendt)); 783 (void) memset(&logoutp, 0x0, sizeof(logoutp)); 784 (void) memset(&res, 0x0, sizeof(res)); 785 conn = make_connection(NULL, NULL, &res, &stid); 786 DEB(9, ("Make connection returns, status = %d", res.status)); 787 788 if (conn == NULL) 789 return res.status; 790 791 sendt.session_id = stid; 792 sendt.response_buffer = NULL; 793 sendt.response_size = 0; 794 sendt.response_used = sendt.response_total = 0; 795 strlcpy((char *)sendt.key, "All", sizeof(sendt.key)); 796 797 /*Call once to get the size of the buffer necessary */ 798 ret = ioctl(driver, ISCSI_SEND_TARGETS, &sendt); 799 800 if (!ret && !sendt.status) { 801 /* Allocate buffer required and call again to retrieve data */ 802 /* We allocate one extra byte so we can place a terminating 0 */ 803 /* at the end of the buffer. */ 804 805 sendt.response_size = sendt.response_total; 806 sendt.response_buffer = calloc(1, sendt.response_size + 1); 807 if (sendt.response_buffer == NULL) 808 rc = ISCSID_STATUS_NO_RESOURCES; 809 else { 810 ret = ioctl(driver, ISCSI_SEND_TARGETS, &sendt); 811 ((uint8_t *)sendt.response_buffer)[sendt.response_size] = 0; 812 813 if (ret || sendt.status) { 814 free(sendt.response_buffer); 815 sendt.response_buffer = NULL; 816 sendt.response_used = 0; 817 if ((rc = sendt.status) == 0) 818 rc = ISCSID_STATUS_GENERAL_ERROR; 819 } 820 } 821 } else if ((rc = sendt.status) == 0) 822 rc = ISCSID_STATUS_GENERAL_ERROR; 823 824 *response_buffer = sendt.response_buffer; 825 *response_size = sendt.response_used; 826 827 logoutp.session_id = stid; 828 ret = ioctl(driver, ISCSI_LOGOUT, &logoutp); 829 /* ignore logout status */ 830 831 free(conn); 832 833 return rc; 834} 835 836 837 838/* 839 * get_version: 840 * Handle GET_VERSION request. 841 * 842 * Returns: Filled get_version_rsp structure. 843 */ 844 845void 846get_version(iscsid_response_t ** prsp, int *prsp_temp) 847{ 848 iscsid_response_t *rsp = *prsp; 849 iscsid_get_version_rsp_t *ver; 850 iscsi_get_version_parameters_t drv_ver; 851 852 rsp = make_rsp(sizeof(iscsid_get_version_rsp_t), prsp, prsp_temp); 853 if (rsp == NULL) 854 return; 855 ver = (iscsid_get_version_rsp_t *)(void *)rsp->parameter; 856 857 ver->interface_version = INTERFACE_VERSION; 858 ver->major = VERSION_MAJOR; 859 ver->minor = VERSION_MINOR; 860 strlcpy ((char *)ver->version_string, VERSION_STRING, sizeof(ver->version_string)); 861 862 ioctl(driver, ISCSI_GET_VERSION, &drv_ver); 863 ver->driver_interface_version = drv_ver.interface_version; 864 ver->driver_major = drv_ver.major; 865 ver->driver_minor = drv_ver.minor; 866 strlcpy ((char *)ver->driver_version_string, (char *)drv_ver.version_string, 867 sizeof (ver->driver_version_string)); 868} 869 870 871/* -------------------------------------------------------------------------- */ 872 873iscsi_register_event_parameters_t event_reg; /* registered event ID */ 874 875 876/* 877 * register_event_handler: 878 * Call driver to register the event handler. 879 * 880 * Returns: 881 * TRUE on success. 882 */ 883 884boolean_t 885register_event_handler(void) 886{ 887 ioctl(driver, ISCSI_REGISTER_EVENT, &event_reg); 888 return event_reg.event_id != 0; 889} 890 891 892/* 893 * deregister_event_handler: 894 * Call driver to deregister the event handler. If the event handler thread 895 * is waiting for an event, this will wake it up and cause it to exit. 896 */ 897 898void 899deregister_event_handler(void) 900{ 901 if (event_reg.event_id) { 902 ioctl(driver, ISCSI_DEREGISTER_EVENT, &event_reg); 903 event_reg.event_id = 0; 904 } 905} 906 907 908/* 909 * event_handler: 910 * Event handler thread. Wait for the driver to generate an event and 911 * process it appropriately. Exits when the driver terminates or the 912 * handler is deregistered because the daemon is terminating. 913 * 914 * Parameter: 915 * par Not used. 916 */ 917 918void * 919/*ARGSUSED*/ 920event_handler(void *par) 921{ 922 void (*termf)(void) = par; 923 iscsi_wait_event_parameters_t evtp; 924 int rc; 925 926 DEB(10, ("Event handler starts")); 927 (void) memset(&evtp, 0x0, sizeof(evtp)); 928 929 evtp.event_id = event_reg.event_id; 930 931 do { 932 rc = ioctl(driver, ISCSI_WAIT_EVENT, &evtp); 933 if (rc != 0) { 934 DEB(10, ("event_handler ioctl failed: %s", 935 strerror(errno))); 936 break; 937 } 938 939 DEB(10, ("Got Event: kind %d, status %d, sid %d, cid %d, reason %d", 940 evtp.event_kind, evtp.status, evtp.session_id, 941 evtp.connection_id, evtp.reason)); 942 943 if (evtp.status) 944 break; 945 946 switch (evtp.event_kind) { 947 case ISCSI_SESSION_TERMINATED: 948 event_kill_session(evtp.session_id); 949 break; 950 951 case ISCSI_CONNECTION_TERMINATED: 952 event_kill_connection(evtp.session_id, evtp.connection_id); 953 break; 954 955 case ISCSI_RECOVER_CONNECTION: 956 event_recover_connection(evtp.session_id, evtp.connection_id); 957 break; 958 default: 959 break; 960 } 961 } while (evtp.event_kind != ISCSI_DRIVER_TERMINATING); 962 963 if (termf != NULL) 964 (*termf)(); 965 966 DEB(10, ("Event handler exits")); 967 968 return NULL; 969} 970 971#if 0 972/* 973 * verify_connection: 974 * Verify that a specific connection still exists, delete it if not. 975 * 976 * Parameter: The connection pointer. 977 * 978 * Returns: The status returned by the driver. 979 */ 980 981uint32_t 982verify_connection(connection_t * conn) 983{ 984 iscsi_conn_status_parameters_t req; 985 session_t *sess = conn->session; 986 987 req.connection_id = conn->entry.sid.id; 988 req.session_id = sess->entry.sid.id; 989 990 ioctl(driver, ISCSI_CONNECTION_STATUS, &req); 991 992 if (req.status) { 993 TAILQ_REMOVE(&sess->connections, &conn->entry, link); 994 sess->num_connections--; 995 free(conn); 996 } 997 DEB(9, ("Verify connection returns status %d", req.status)); 998 return req.status; 999} 1000 1001#endif 1002