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