1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2000 by Cisco Systems, Inc. All rights reserved. 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * iSCSI protocol login and enumeration 27 */ 28 29 #include "iscsi.h" 30 #include <sys/iscsi_protocol.h> 31 #include <sys/scsi/adapters/iscsi_door.h> 32 33 boolean_t iscsi_login_logging = B_FALSE; 34 35 /* internal login protocol interfaces */ 36 static iscsi_status_t iscsi_login(iscsi_conn_t *icp, 37 uint8_t *status_class, uint8_t *status_detail); 38 static int iscsi_add_text(idm_pdu_t *text_pdu, 39 int max_data_length, char *param, char *value); 40 static int iscsi_find_key_value(char *param, char *ihp, char *pdu_end, 41 char **value_start, char **value_end); 42 static void iscsi_null_callback(void *user_handle, void *message_handle, 43 int auth_status); 44 static iscsi_status_t iscsi_process_login_response(iscsi_conn_t *icp, 45 iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length); 46 static iscsi_status_t iscsi_make_login_pdu(iscsi_conn_t *icp, 47 idm_pdu_t *text_pdu, char *data, int max_data_length); 48 static iscsi_status_t iscsi_update_address(iscsi_conn_t *icp, 49 char *address); 50 static char *iscsi_login_failure_str(uchar_t status_class, 51 uchar_t status_detail); 52 static void iscsi_login_end(iscsi_conn_t *icp, 53 iscsi_status_t status, iscsi_task_t *itp); 54 static iscsi_status_t iscsi_login_connect(iscsi_conn_t *icp); 55 static void iscsi_login_disconnect(iscsi_conn_t *icp); 56 static void iscsi_notice_key_values(iscsi_conn_t *icp); 57 58 #define ISCSI_LOGIN_RETRY_DELAY 5 /* seconds */ 59 60 #define ISCSI_LOGIN_TRANSIT_FFP(flags) \ 61 (!(flags & ISCSI_FLAG_LOGIN_CONTINUE) && \ 62 (flags & ISCSI_FLAG_LOGIN_TRANSIT) && \ 63 (ISCSI_LOGIN_CURRENT_STAGE(flags) == \ 64 ISCSI_OP_PARMS_NEGOTIATION_STAGE) && \ 65 (ISCSI_LOGIN_NEXT_STAGE(flags) == \ 66 ISCSI_FULL_FEATURE_PHASE)) 67 68 /* 69 * +--------------------------------------------------------------------+ 70 * | External Login Interface | 71 * +--------------------------------------------------------------------+ 72 */ 73 74 /* 75 * iscsi_login_start - connect and perform iscsi protocol login 76 */ 77 iscsi_status_t 78 iscsi_login_start(void *arg) 79 { 80 iscsi_task_t *itp = (iscsi_task_t *)arg; 81 iscsi_status_t rval = ISCSI_STATUS_LOGIN_FAILED; 82 iscsi_conn_t *icp; 83 iscsi_sess_t *isp; 84 iscsi_hba_t *ihp; 85 unsigned char status_class; 86 unsigned char status_detail; 87 88 ASSERT(itp != NULL); 89 icp = (iscsi_conn_t *)itp->t_arg; 90 ASSERT(icp != NULL); 91 isp = icp->conn_sess; 92 ASSERT(isp != NULL); 93 ihp = isp->sess_hba; 94 ASSERT(ihp != NULL); 95 96 login_start: 97 ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) || 98 (icp->conn_state == ISCSI_CONN_STATE_FAILED) || 99 (icp->conn_state == ISCSI_CONN_STATE_POLLING)); 100 101 icp->conn_state_ffp = B_FALSE; 102 103 /* reset connection statsn */ 104 icp->conn_expstatsn = 0; 105 icp->conn_laststatsn = 0; 106 107 /* sync up authentication information */ 108 (void) iscsi_sess_set_auth(isp); 109 110 /* sync up login and session parameters */ 111 if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) { 112 /* unable to sync params. fail connection attempts */ 113 iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp); 114 return (ISCSI_STATUS_LOGIN_FAILED); 115 } 116 117 /* 118 * Attempt to open TCP connection, associated IDM connection will 119 * have a hold on it that must be released after the call to 120 * iscsi_login() below. 121 */ 122 if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) { 123 if ((isp->sess_boot == B_TRUE) && 124 (ihp->hba_service_status_overwrite == B_TRUE) && 125 (isp->sess_boot_nic_reset == B_FALSE)) { 126 /* 127 * The connection to boot target failed 128 * before the system fully started. 129 * Reset the boot nic to the settings from 130 * firmware before retrying the connect to 131 * save the the system. 132 */ 133 if (iscsi_net_interface(B_TRUE) == 134 ISCSI_STATUS_SUCCESS) { 135 isp->sess_boot_nic_reset = B_TRUE; 136 } 137 } 138 /* retry this failure */ 139 goto login_retry; 140 } 141 142 /* 143 * allocate response buffer with based on default max 144 * transfer size. This size might shift during login. 145 */ 146 icp->conn_login_max_data_length = 147 icp->conn_params.max_xmit_data_seg_len; 148 icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length, 149 KM_SLEEP); 150 151 /* 152 * Start protocol login, upon return we will be either logged in 153 * or disconnected 154 */ 155 rval = iscsi_login(icp, &status_class, &status_detail); 156 157 /* done with buffer */ 158 kmem_free(icp->conn_login_data, icp->conn_login_max_data_length); 159 160 /* Release connection hold */ 161 idm_conn_rele(icp->conn_ic); 162 163 /* hard failure in login */ 164 if (!ISCSI_SUCCESS(rval)) { 165 /* 166 * We should just give up retry if these failures are 167 * detected. 168 */ 169 switch (rval) { 170 /* 171 * We should just give up retry if these 172 * failures are detected. 173 */ 174 case ISCSI_STATUS_AUTHENTICATION_FAILED: 175 case ISCSI_STATUS_INTERNAL_ERROR: 176 case ISCSI_STATUS_VERSION_MISMATCH: 177 case ISCSI_STATUS_NEGO_FAIL: 178 /* we don't want to retry this failure */ 179 iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp); 180 return (ISCSI_STATUS_LOGIN_FAILED); 181 default: 182 /* retry this failure */ 183 goto login_retry; 184 } 185 } 186 187 /* soft failure with reason */ 188 switch (status_class) { 189 case ISCSI_STATUS_CLASS_SUCCESS: 190 /* login was successful */ 191 iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp); 192 return (ISCSI_STATUS_SUCCESS); 193 case ISCSI_STATUS_CLASS_REDIRECT: 194 /* Retry at the redirected address */ 195 goto login_start; 196 case ISCSI_STATUS_CLASS_TARGET_ERR: 197 /* retry this failure */ 198 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 199 "%s (0x%02x/0x%02x)", icp->conn_oid, 200 iscsi_login_failure_str(status_class, status_detail), 201 status_class, status_detail); 202 goto login_retry; 203 case ISCSI_STATUS_CLASS_INITIATOR_ERR: 204 default: 205 /* All other errors are hard failures */ 206 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 207 "%s (0x%02x/0x%02x) Target: %s, TPGT: %d", 208 icp->conn_oid, 209 iscsi_login_failure_str(status_class, status_detail), 210 status_class, status_detail, isp->sess_name, 211 isp->sess_tpgt_conf); 212 213 /* we don't want to retry this failure */ 214 iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp); 215 break; 216 } 217 218 return (ISCSI_STATUS_LOGIN_FAILED); 219 220 login_retry: 221 /* retry this failure if we haven't run out of time */ 222 if (icp->conn_login_max > ddi_get_lbolt()) { 223 224 if (icp->conn_state == ISCSI_CONN_STATE_POLLING) { 225 icp->conn_login_min = ddi_get_lbolt() + 226 SEC_TO_TICK(icp->conn_tunable_params. 227 polling_login_delay); 228 } else { 229 icp->conn_login_min = ddi_get_lbolt() + 230 SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY); 231 } 232 233 if (itp->t_blocking == B_TRUE) { 234 goto login_start; 235 } else { 236 if (ddi_taskq_dispatch(isp->sess_taskq, 237 (void(*)())iscsi_login_start, itp, DDI_SLEEP) != 238 DDI_SUCCESS) { 239 iscsi_login_end(icp, 240 ISCSI_STATUS_LOGIN_TIMED_OUT, itp); 241 } 242 return (ISCSI_STATUS_SUCCESS); 243 } 244 } else { 245 /* Retries exceeded */ 246 iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp); 247 } 248 249 return (ISCSI_STATUS_LOGIN_FAILED); 250 } 251 252 static void 253 iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp) 254 { 255 iscsi_sess_t *isp; 256 257 ASSERT(icp != NULL); 258 isp = icp->conn_sess; 259 ASSERT(isp != NULL); 260 261 if (status == ISCSI_STATUS_SUCCESS) { 262 /* Inform IDM of the relevant negotiated values */ 263 iscsi_notice_key_values(icp); 264 265 /* We are now logged in */ 266 iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN); 267 268 /* startup TX thread */ 269 (void) iscsi_thread_start(icp->conn_tx_thread); 270 271 /* 272 * Move login state machine to LOGIN_FFP. This will 273 * release the taskq thread handling the CN_FFP_ENABLED 274 * allowing the IDM connection state machine to resume 275 * processing events 276 */ 277 iscsi_login_update_state(icp, LOGIN_FFP); 278 279 /* Notify the session that a connection is logged in */ 280 mutex_enter(&isp->sess_state_mutex); 281 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1); 282 mutex_exit(&isp->sess_state_mutex); 283 } else { 284 /* If login failed reset nego tpgt */ 285 isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT; 286 287 mutex_enter(&icp->conn_state_mutex); 288 switch (icp->conn_state) { 289 case ISCSI_CONN_STATE_IN_LOGIN: 290 iscsi_conn_update_state_locked(icp, 291 ISCSI_CONN_STATE_FREE); 292 mutex_exit(&icp->conn_state_mutex); 293 break; 294 case ISCSI_CONN_STATE_FAILED: 295 if (status == ISCSI_STATUS_LOGIN_FAILED) { 296 iscsi_conn_update_state_locked(icp, 297 ISCSI_CONN_STATE_FREE); 298 } else { 299 /* ISCSI_STATUS_LOGIN_TIMED_OUT */ 300 iscsi_conn_update_state_locked(icp, 301 ISCSI_CONN_STATE_POLLING); 302 } 303 mutex_exit(&icp->conn_state_mutex); 304 305 mutex_enter(&isp->sess_state_mutex); 306 iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6); 307 mutex_exit(&isp->sess_state_mutex); 308 309 if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) { 310 iscsi_conn_retry(isp, icp); 311 } 312 break; 313 case ISCSI_CONN_STATE_POLLING: 314 if (status == ISCSI_STATUS_LOGIN_FAILED) { 315 iscsi_conn_update_state_locked(icp, 316 ISCSI_CONN_STATE_FREE); 317 mutex_exit(&icp->conn_state_mutex); 318 319 mutex_enter(&isp->sess_state_mutex); 320 iscsi_sess_state_machine(isp, 321 ISCSI_SESS_EVENT_N6); 322 mutex_exit(&isp->sess_state_mutex); 323 } else { 324 /* ISCSI_STATUS_LOGIN_TIMED_OUT */ 325 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 326 mutex_exit(&icp->conn_state_mutex); 327 328 iscsi_conn_retry(isp, icp); 329 } else { 330 iscsi_conn_update_state_locked(icp, 331 ISCSI_CONN_STATE_FREE); 332 mutex_exit(&icp->conn_state_mutex); 333 } 334 } 335 break; 336 case ISCSI_CONN_STATE_FREE: 337 mutex_exit(&icp->conn_state_mutex); 338 break; 339 default: 340 mutex_exit(&icp->conn_state_mutex); 341 ASSERT(0); 342 break; 343 } 344 } 345 346 if (itp->t_blocking == B_FALSE) { 347 kmem_free(itp, sizeof (iscsi_task_t)); 348 } 349 350 isp->sess_boot_nic_reset = B_FALSE; 351 } 352 353 /* 354 * +--------------------------------------------------------------------+ 355 * | Begin of protocol login routines | 356 * +--------------------------------------------------------------------+ 357 */ 358 359 /* 360 * iscsi_login - Attempt to login to the target. The caller 361 * must check the status class to determine if the login succeeded. 362 * A return of 1 does not mean the login succeeded, it just means 363 * this function worked, and the status class is valid info. This 364 * allows the caller to decide whether or not to retry logins, so 365 * that we don't have any policy logic here. 366 */ 367 iscsi_status_t 368 iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail) 369 { 370 iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR; 371 struct iscsi_sess *isp = NULL; 372 IscsiAuthClient *auth_client = NULL; 373 int max_data_length = 0; 374 char *data = NULL; 375 idm_pdu_t *text_pdu; 376 char *buffer; 377 size_t bufsize; 378 iscsi_login_rsp_hdr_t *ilrhp; 379 clock_t response_timeout, timeout_result; 380 381 buffer = icp->conn_login_data; 382 bufsize = icp->conn_login_max_data_length; 383 384 ASSERT(icp != NULL); 385 ASSERT(buffer != NULL); 386 ASSERT(status_class != NULL); 387 ASSERT(status_detail != NULL); 388 isp = icp->conn_sess; 389 ASSERT(isp != NULL); 390 391 /* 392 * prepare the connection, hold IDM connection until login completes 393 */ 394 icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE; 395 icp->conn_partial_response = 0; 396 397 if (isp->sess_auth.auth_buffers && 398 isp->sess_auth.num_auth_buffers) { 399 400 auth_client = (IscsiAuthClient *)isp-> 401 sess_auth.auth_buffers[0].address; 402 403 /* 404 * prepare for authentication 405 */ 406 if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator, 407 isp->sess_auth.num_auth_buffers, 408 isp->sess_auth.auth_buffers) != 409 iscsiAuthStatusNoError) { 410 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 411 "unable to initialize authentication", 412 icp->conn_oid); 413 iscsi_login_disconnect(icp); 414 iscsi_login_update_state(icp, LOGIN_DONE); 415 return (ISCSI_STATUS_INTERNAL_ERROR); 416 } 417 418 if (iscsiAuthClientSetVersion(auth_client, 419 iscsiAuthVersionRfc) != iscsiAuthStatusNoError) { 420 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 421 "unable to set authentication", icp->conn_oid); 422 goto iscsi_login_done; 423 } 424 425 if (isp->sess_auth.username && 426 (iscsiAuthClientSetUsername(auth_client, 427 isp->sess_auth.username) != 428 iscsiAuthStatusNoError)) { 429 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 430 "unable to set username", icp->conn_oid); 431 goto iscsi_login_done; 432 } 433 434 if (isp->sess_auth.password && 435 (iscsiAuthClientSetPassword(auth_client, 436 isp->sess_auth.password, isp->sess_auth.password_length) != 437 iscsiAuthStatusNoError)) { 438 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 439 "unable to set password", icp->conn_oid); 440 goto iscsi_login_done; 441 } 442 443 if (iscsiAuthClientSetIpSec(auth_client, 1) != 444 iscsiAuthStatusNoError) { 445 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 446 "unable to set ipsec", icp->conn_oid); 447 goto iscsi_login_done; 448 } 449 450 if (iscsiAuthClientSetAuthRemote(auth_client, 451 isp->sess_auth.bidirectional_auth) != 452 iscsiAuthStatusNoError) { 453 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 454 "unable to set remote authentication", 455 icp->conn_oid); 456 goto iscsi_login_done; 457 } 458 } 459 460 /* 461 * exchange PDUs until the login stage is complete, or an error occurs 462 */ 463 do { 464 /* setup */ 465 bzero(buffer, bufsize); 466 data = buffer; 467 max_data_length = bufsize; 468 rval = ISCSI_STATUS_INTERNAL_ERROR; 469 470 text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0); 471 idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL); 472 473 /* 474 * fill in the PDU header and text data based on the 475 * login stage that we're in 476 */ 477 rval = iscsi_make_login_pdu(icp, text_pdu, data, 478 max_data_length); 479 if (!ISCSI_SUCCESS(rval)) { 480 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 481 "unable to make login pdu", icp->conn_oid); 482 goto iscsi_login_done; 483 } 484 485 mutex_enter(&icp->conn_login_mutex); 486 /* 487 * Make sure we are still in LOGIN_START or LOGIN_RX 488 * state before switching to LOGIN_TX. It's possible 489 * for a connection failure to move us to LOGIN_ERROR 490 * before we get to this point. 491 */ 492 if (((icp->conn_login_state != LOGIN_READY) && 493 (icp->conn_login_state != LOGIN_RX)) || 494 !icp->conn_state_idm_connected) { 495 /* Error occurred */ 496 mutex_exit(&icp->conn_login_mutex); 497 rval = (ISCSI_STATUS_INTERNAL_ERROR); 498 goto iscsi_login_done; 499 } 500 501 iscsi_login_update_state_locked(icp, LOGIN_TX); 502 icp->conn_login_data = data; 503 icp->conn_login_max_data_length = max_data_length; 504 505 /* 506 * send a PDU to the target. This is asynchronous but 507 * we don't have any particular need for a TX completion 508 * notification since we are going to block waiting for the 509 * receive. 510 */ 511 response_timeout = ddi_get_lbolt() + 512 SEC_TO_TICK(icp->conn_tunable_params. 513 recv_login_rsp_timeout); 514 idm_pdu_tx(text_pdu); 515 516 /* 517 * Wait for login failure indication or login RX. 518 * Handler for login response PDU will copy any data into 519 * the buffer pointed to by icp->conn_login_data 520 */ 521 while (icp->conn_login_state == LOGIN_TX) { 522 timeout_result = cv_timedwait(&icp->conn_login_cv, 523 &icp->conn_login_mutex, response_timeout); 524 if (timeout_result == -1) 525 break; 526 } 527 528 if (icp->conn_login_state != LOGIN_RX) { 529 mutex_exit(&icp->conn_login_mutex); 530 rval = (ISCSI_STATUS_INTERNAL_ERROR); 531 goto iscsi_login_done; 532 } 533 mutex_exit(&icp->conn_login_mutex); 534 535 /* check the PDU response type */ 536 ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr; 537 if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) { 538 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 539 "received invalid login response (0x%02x)", 540 icp->conn_oid, ilrhp->opcode); 541 rval = (ISCSI_STATUS_PROTOCOL_ERROR); 542 goto iscsi_login_done; 543 } 544 545 /* 546 * give the caller the status class and detail from the 547 * last login response PDU received 548 */ 549 if (status_class) { 550 *status_class = ilrhp->status_class; 551 } 552 if (status_detail) { 553 *status_detail = ilrhp->status_detail; 554 } 555 556 switch (ilrhp->status_class) { 557 case ISCSI_STATUS_CLASS_SUCCESS: 558 /* 559 * process this response and possibly continue 560 * sending PDUs 561 */ 562 rval = iscsi_process_login_response(icp, 563 ilrhp, (char *)icp->conn_login_data, 564 icp->conn_login_max_data_length); 565 /* pass back whatever error we discovered */ 566 if (!ISCSI_SUCCESS(rval)) { 567 if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) { 568 /* 569 * iSCSI connection transit to next 570 * FFP stage while iscsi params 571 * ngeotiate error, LOGIN_ERROR 572 * marked so CN_FFP_ENABLED can 573 * be fully handled before 574 * CN_FFP_DISABLED can be processed. 575 */ 576 iscsi_login_update_state(icp, 577 LOGIN_ERROR); 578 } 579 goto iscsi_login_done; 580 } 581 582 break; 583 case ISCSI_STATUS_CLASS_REDIRECT: 584 /* 585 * we need to process this response to get the 586 * TargetAddress of the redirect, but we don't 587 * care about the return code. 588 */ 589 (void) iscsi_process_login_response(icp, 590 ilrhp, (char *)icp->conn_login_data, 591 icp->conn_login_max_data_length); 592 rval = ISCSI_STATUS_SUCCESS; 593 goto iscsi_login_done; 594 case ISCSI_STATUS_CLASS_INITIATOR_ERR: 595 if (ilrhp->status_detail == 596 ISCSI_LOGIN_STATUS_AUTH_FAILED) { 597 cmn_err(CE_WARN, "iscsi connection(%u) login " 598 "failed - login failed to authenticate " 599 "with target", icp->conn_oid); 600 } 601 rval = ISCSI_STATUS_SUCCESS; 602 goto iscsi_login_done; 603 default: 604 /* 605 * some sort of error, login terminated unsuccessfully, 606 * though this function did it's job. the caller must 607 * check the status_class and status_detail and decide 608 * what to do next. 609 */ 610 rval = ISCSI_STATUS_SUCCESS; 611 goto iscsi_login_done; 612 } 613 614 } while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE); 615 616 rval = ISCSI_STATUS_SUCCESS; 617 618 iscsi_login_done: 619 if (auth_client) { 620 if (iscsiAuthClientFinish(auth_client) != 621 iscsiAuthStatusNoError) { 622 cmn_err(CE_WARN, "iscsi connection(%u) login " 623 "failed - login failed to authenticate " 624 "with target", icp->conn_oid); 625 if (ISCSI_SUCCESS(rval)) 626 rval = ISCSI_STATUS_INTERNAL_ERROR; 627 } 628 } 629 630 if (ISCSI_SUCCESS(rval) && 631 (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) { 632 mutex_enter(&icp->conn_state_mutex); 633 while (!icp->conn_state_ffp) 634 cv_wait(&icp->conn_state_change, 635 &icp->conn_state_mutex); 636 mutex_exit(&icp->conn_state_mutex); 637 } else { 638 iscsi_login_disconnect(icp); 639 } 640 641 iscsi_login_update_state(icp, LOGIN_DONE); 642 643 return (rval); 644 } 645 646 647 /* 648 * iscsi_make_login_pdu - 649 * 650 */ 651 static iscsi_status_t 652 iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu, 653 char *data, int max_data_length) 654 { 655 struct iscsi_sess *isp = NULL; 656 int transit = 0; 657 iscsi_hdr_t *ihp = text_pdu->isp_hdr; 658 iscsi_login_hdr_t *ilhp = 659 (iscsi_login_hdr_t *)text_pdu->isp_hdr; 660 IscsiAuthClient *auth_client = NULL; 661 int keytype = 0; 662 int rc = 0; 663 char value[iscsiAuthStringMaxLength]; 664 665 ASSERT(icp != NULL); 666 ASSERT(text_pdu != NULL); 667 isp = icp->conn_sess; 668 ASSERT(isp != NULL); 669 670 auth_client = 671 (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ? 672 (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL; 673 674 /* 675 * initialize the PDU header 676 */ 677 bzero(ilhp, sizeof (*ilhp)); 678 ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE; 679 ilhp->cid = icp->conn_cid; 680 bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid)); 681 ilhp->tsid = 0; 682 683 /* 684 * Set data buffer pointer. The calls to iscsi_add_text will update the 685 * data length. 686 */ 687 text_pdu->isp_data = (uint8_t *)data; 688 689 /* don't increment on immediate */ 690 ilhp->cmdsn = htonl(isp->sess_cmdsn); 691 692 ilhp->min_version = ISCSI_DRAFT20_VERSION; 693 ilhp->max_version = ISCSI_DRAFT20_VERSION; 694 695 /* 696 * we have to send 0 until full-feature stage 697 */ 698 ilhp->expstatsn = htonl(icp->conn_expstatsn); 699 700 /* 701 * the very first Login PDU has some additional requirements, 702 * * and we need to decide what stage to start in. 703 */ 704 if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) { 705 if ((isp->sess_hba->hba_name) && 706 (isp->sess_hba->hba_name[0])) { 707 if (!iscsi_add_text(text_pdu, max_data_length, 708 "InitiatorName", 709 (char *)isp->sess_hba->hba_name)) { 710 return (ISCSI_STATUS_INTERNAL_ERROR); 711 } 712 } else { 713 cmn_err(CE_WARN, "iscsi connection(%u) login " 714 "failed - initiator name is required", 715 icp->conn_oid); 716 return (ISCSI_STATUS_INTERNAL_ERROR); 717 } 718 719 if ((isp->sess_hba->hba_alias) && 720 (isp->sess_hba->hba_alias[0])) { 721 if (!iscsi_add_text(text_pdu, max_data_length, 722 "InitiatorAlias", 723 (char *)isp->sess_hba->hba_alias)) { 724 return (ISCSI_STATUS_INTERNAL_ERROR); 725 } 726 } 727 728 if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) { 729 if (isp->sess_name[0] != '\0') { 730 if (!iscsi_add_text(text_pdu, max_data_length, 731 "TargetName", (char *)isp->sess_name)) { 732 return (ISCSI_STATUS_INTERNAL_ERROR); 733 } 734 } 735 736 if (!iscsi_add_text(text_pdu, max_data_length, 737 "SessionType", "Normal")) { 738 return (ISCSI_STATUS_INTERNAL_ERROR); 739 } 740 } else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) { 741 if (!iscsi_add_text(text_pdu, max_data_length, 742 "SessionType", "Discovery")) { 743 return (ISCSI_STATUS_INTERNAL_ERROR); 744 } 745 } else { 746 return (ISCSI_STATUS_INTERNAL_ERROR); 747 } 748 749 if (auth_client) { 750 /* we're prepared to do authentication */ 751 icp->conn_current_stage = 752 ISCSI_SECURITY_NEGOTIATION_STAGE; 753 } else { 754 /* can't do any authentication, skip that stage */ 755 icp->conn_current_stage = 756 ISCSI_OP_PARMS_NEGOTIATION_STAGE; 757 } 758 } 759 760 /* 761 * fill in text based on the stage 762 */ 763 switch (icp->conn_current_stage) { 764 case ISCSI_OP_PARMS_NEGOTIATION_STAGE: 765 /* 766 * we always try to go from op params to full 767 * feature stage 768 */ 769 icp->conn_next_stage = ISCSI_FULL_FEATURE_PHASE; 770 transit = 1; 771 772 /* 773 * The terminology here may have gotten dated. A partial 774 * response is a login response that doesn't complete a 775 * login. If we haven't gotten a partial response, then 776 * either we shouldn't be here, or we just switched to 777 * this stage, and need to start offering keys. 778 */ 779 if (!icp->conn_partial_response) { 780 /* 781 * request the desired settings the first time 782 * we are in this stage 783 */ 784 switch (icp->conn_params.header_digest) { 785 case ISCSI_DIGEST_NONE: 786 if (!iscsi_add_text(text_pdu, 787 max_data_length, "HeaderDigest", "None")) { 788 return (ISCSI_STATUS_INTERNAL_ERROR); 789 } 790 break; 791 case ISCSI_DIGEST_CRC32C: 792 if (!iscsi_add_text(text_pdu, 793 max_data_length, 794 "HeaderDigest", "CRC32C")) { 795 return (ISCSI_STATUS_INTERNAL_ERROR); 796 } 797 break; 798 case ISCSI_DIGEST_CRC32C_NONE: 799 if (!iscsi_add_text(text_pdu, 800 max_data_length, "HeaderDigest", 801 "CRC32C,None")) { 802 return (ISCSI_STATUS_INTERNAL_ERROR); 803 } 804 break; 805 default: 806 case ISCSI_DIGEST_NONE_CRC32C: 807 if (!iscsi_add_text(text_pdu, 808 max_data_length, "HeaderDigest", 809 "None,CRC32C")) { 810 return (ISCSI_STATUS_INTERNAL_ERROR); 811 } 812 break; 813 } 814 815 switch (icp->conn_params.data_digest) { 816 case ISCSI_DIGEST_NONE: 817 if (!iscsi_add_text(text_pdu, 818 max_data_length, "DataDigest", "None")) { 819 return (ISCSI_STATUS_INTERNAL_ERROR); 820 } 821 break; 822 case ISCSI_DIGEST_CRC32C: 823 if (!iscsi_add_text(text_pdu, 824 max_data_length, "DataDigest", "CRC32C")) { 825 return (ISCSI_STATUS_INTERNAL_ERROR); 826 } 827 break; 828 case ISCSI_DIGEST_CRC32C_NONE: 829 if (!iscsi_add_text(text_pdu, 830 max_data_length, "DataDigest", 831 "CRC32C,None")) { 832 return (ISCSI_STATUS_INTERNAL_ERROR); 833 } 834 break; 835 default: 836 case ISCSI_DIGEST_NONE_CRC32C: 837 if (!iscsi_add_text(text_pdu, 838 max_data_length, "DataDigest", 839 "None,CRC32C")) { 840 return (ISCSI_STATUS_INTERNAL_ERROR); 841 } 842 break; 843 } 844 845 (void) sprintf(value, "%d", 846 icp->conn_params.max_recv_data_seg_len); 847 if (!iscsi_add_text(text_pdu, max_data_length, 848 "MaxRecvDataSegmentLength", value)) { 849 return (ISCSI_STATUS_INTERNAL_ERROR); 850 } 851 852 (void) sprintf(value, "%d", 853 icp->conn_params.default_time_to_wait); 854 if (!iscsi_add_text(text_pdu, 855 max_data_length, "DefaultTime2Wait", value)) { 856 return (ISCSI_STATUS_INTERNAL_ERROR); 857 } 858 859 (void) sprintf(value, "%d", 860 icp->conn_params.default_time_to_retain); 861 if (!iscsi_add_text(text_pdu, 862 max_data_length, "DefaultTime2Retain", value)) { 863 return (ISCSI_STATUS_INTERNAL_ERROR); 864 } 865 866 (void) sprintf(value, "%d", 867 icp->conn_params.error_recovery_level); 868 if (!iscsi_add_text(text_pdu, 869 max_data_length, "ErrorRecoveryLevel", "0")) { 870 return (ISCSI_STATUS_INTERNAL_ERROR); 871 } 872 873 if (!iscsi_add_text(text_pdu, 874 max_data_length, "IFMarker", 875 icp->conn_params.ifmarker ? "Yes" : "No")) { 876 return (ISCSI_STATUS_INTERNAL_ERROR); 877 } 878 879 if (!iscsi_add_text(text_pdu, 880 max_data_length, "OFMarker", 881 icp->conn_params.ofmarker ? "Yes" : "No")) { 882 return (ISCSI_STATUS_INTERNAL_ERROR); 883 } 884 885 /* 886 * The following login parameters are "Irrelevant" 887 * for discovery sessions 888 */ 889 if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) { 890 891 if (!iscsi_add_text(text_pdu, 892 max_data_length, "InitialR2T", 893 icp->conn_params.initial_r2t ? 894 "Yes" : "No")) { 895 return (ISCSI_STATUS_INTERNAL_ERROR); 896 } 897 898 if (!iscsi_add_text(text_pdu, 899 max_data_length, "ImmediateData", 900 icp->conn_params.immediate_data ? 901 "Yes" : "No")) { 902 return (ISCSI_STATUS_INTERNAL_ERROR); 903 } 904 905 (void) sprintf(value, "%d", 906 icp->conn_params.max_burst_length); 907 if (!iscsi_add_text(text_pdu, 908 max_data_length, "MaxBurstLength", value)) { 909 return (ISCSI_STATUS_INTERNAL_ERROR); 910 } 911 912 (void) sprintf(value, "%d", 913 icp->conn_params.first_burst_length); 914 if (!iscsi_add_text(text_pdu, max_data_length, 915 "FirstBurstLength", value)) { 916 return (ISCSI_STATUS_INTERNAL_ERROR); 917 } 918 919 (void) sprintf(value, "%d", 920 icp->conn_params.max_outstanding_r2t); 921 if (!iscsi_add_text(text_pdu, max_data_length, 922 "MaxOutstandingR2T", value)) { 923 return (ISCSI_STATUS_INTERNAL_ERROR); 924 } 925 926 (void) sprintf(value, "%d", 927 icp->conn_params.max_connections); 928 if (!iscsi_add_text(text_pdu, max_data_length, 929 "MaxConnections", value)) { 930 return (ISCSI_STATUS_INTERNAL_ERROR); 931 } 932 933 if (!iscsi_add_text(text_pdu, 934 max_data_length, "DataPDUInOrder", 935 icp->conn_params.data_pdu_in_order ? 936 "Yes" : "No")) { 937 return (ISCSI_STATUS_INTERNAL_ERROR); 938 } 939 940 if (!iscsi_add_text(text_pdu, 941 max_data_length, "DataSequenceInOrder", 942 icp->conn_params.data_sequence_in_order ? 943 "Yes" : "No")) { 944 return (ISCSI_STATUS_INTERNAL_ERROR); 945 } 946 } 947 } 948 break; 949 950 case ISCSI_SECURITY_NEGOTIATION_STAGE: 951 keytype = iscsiAuthKeyTypeNone; 952 rc = iscsiAuthClientSendTransitBit(auth_client, &transit); 953 954 /* 955 * see if we're ready for a stage change 956 */ 957 if (rc == iscsiAuthStatusNoError) { 958 if (transit) { 959 icp->conn_next_stage = 960 ISCSI_OP_PARMS_NEGOTIATION_STAGE; 961 } else { 962 icp->conn_next_stage = 963 ISCSI_SECURITY_NEGOTIATION_STAGE; 964 } 965 } else { 966 return (ISCSI_STATUS_INTERNAL_ERROR); 967 } 968 969 /* 970 * enumerate all the keys the auth code might want to send 971 */ 972 while (iscsiAuthClientGetNextKeyType(&keytype) == 973 iscsiAuthStatusNoError) { 974 int present = 0; 975 char *key = (char *)iscsiAuthClientGetKeyName(keytype); 976 int key_length = key ? strlen(key) : 0; 977 int pdu_length = text_pdu->isp_datalen; 978 char *auth_value = data + pdu_length + key_length + 1; 979 unsigned int max_length = max_data_length - 980 (pdu_length + key_length + 1); 981 982 /* 983 * add the key/value pairs the auth code wants to 984 * send directly to the PDU, since they could in 985 * theory be large. 986 */ 987 rc = iscsiAuthClientSendKeyValue(auth_client, keytype, 988 &present, auth_value, max_length); 989 if ((rc == iscsiAuthStatusNoError) && present) { 990 /* 991 * actually fill in the key 992 */ 993 (void) strncpy(&data[pdu_length], key, 994 key_length); 995 pdu_length += key_length; 996 data[pdu_length] = '='; 997 pdu_length++; 998 /* 999 * adjust the PDU's data segment length to 1000 * include the value and trailing NULL 1001 */ 1002 pdu_length += strlen(auth_value) + 1; 1003 text_pdu->isp_datalen = pdu_length; 1004 hton24(ihp->dlength, pdu_length); 1005 } 1006 } 1007 1008 break; 1009 case ISCSI_FULL_FEATURE_PHASE: 1010 cmn_err(CE_WARN, "iscsi connection(%u) login " 1011 "failed - can't send login in full feature stage", 1012 icp->conn_oid); 1013 return (ISCSI_STATUS_INTERNAL_ERROR); 1014 default: 1015 cmn_err(CE_WARN, "iscsi connection(%u) login " 1016 "failed - can't send login in unknown stage (%d)", 1017 icp->conn_oid, icp->conn_current_stage); 1018 return (ISCSI_STATUS_INTERNAL_ERROR); 1019 } 1020 1021 /* fill in the flags */ 1022 ilhp->flags = icp->conn_current_stage << 2; 1023 if (transit) { 1024 /* transit to the next stage */ 1025 ilhp->flags |= icp->conn_next_stage; 1026 ilhp->flags |= ISCSI_FLAG_LOGIN_TRANSIT; 1027 } else { 1028 /* next == current */ 1029 ilhp->flags |= icp->conn_current_stage; 1030 } 1031 1032 return (ISCSI_STATUS_SUCCESS); 1033 } 1034 1035 1036 /* 1037 * iscsi_process_login_response - This assumes the text data is 1038 * always NUL terminated. The caller can always arrange for that by 1039 * using a slightly larger buffer than the max PDU size, and then 1040 * appending a NUL to the PDU. 1041 */ 1042 static iscsi_status_t 1043 iscsi_process_login_response(iscsi_conn_t *icp, 1044 iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length) 1045 { 1046 iscsi_sess_t *isp = NULL; 1047 IscsiAuthClient *auth_client = NULL; 1048 int transit = 0; 1049 char *text = data; 1050 char *end = NULL; 1051 int pdu_current_stage = 0; 1052 int pdu_next_stage = 0; 1053 int debug_status = 0; 1054 unsigned long tmp; 1055 char *tmpe; 1056 boolean_t fbl_irrelevant = B_FALSE; 1057 1058 ASSERT(icp != NULL); 1059 ASSERT(ilrhp != NULL); 1060 ASSERT(data != NULL); 1061 isp = icp->conn_sess; 1062 ASSERT(isp != NULL); 1063 1064 auth_client = 1065 (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ? 1066 (IscsiAuthClient *) isp->sess_auth.auth_buffers[0].address : NULL; 1067 transit = ilrhp->flags & ISCSI_FLAG_LOGIN_TRANSIT; 1068 1069 /* verify the initial buffer was big enough to hold everything */ 1070 end = text + ntoh24(ilrhp->dlength) + 1; 1071 if (end >= (data + max_data_length)) { 1072 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 1073 "buffer too small", icp->conn_oid); 1074 return (ISCSI_STATUS_INTERNAL_ERROR); 1075 } 1076 *end = '\0'; 1077 1078 /* if the response status was success, sanity check the response */ 1079 if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 1080 /* check the active version */ 1081 if (ilrhp->active_version != ISCSI_DRAFT20_VERSION) { 1082 cmn_err(CE_WARN, "iscsi connection(%u) login " 1083 "failed - target version incompatible " 1084 "received:0x%0x2x expected:0x%02x", 1085 icp->conn_oid, ilrhp->active_version, 1086 ISCSI_DRAFT20_VERSION); 1087 return (ISCSI_STATUS_VERSION_MISMATCH); 1088 } 1089 1090 /* make sure the current stage matches */ 1091 pdu_current_stage = (ilrhp->flags & 1092 ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; 1093 if (pdu_current_stage != icp->conn_current_stage) { 1094 cmn_err(CE_WARN, "iscsi connection(%u) login " 1095 "failed - login response contained invalid " 1096 "stage %d", icp->conn_oid, pdu_current_stage); 1097 return (ISCSI_STATUS_PROTOCOL_ERROR); 1098 } 1099 1100 /* 1101 * Make sure that we're actually advancing 1102 * if the T-bit is set 1103 */ 1104 pdu_next_stage = ilrhp->flags & 1105 ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; 1106 if (transit && (pdu_next_stage <= icp->conn_current_stage)) { 1107 cmn_err(CE_WARN, "iscsi connection(%u) login " 1108 "failed - login response wants to go to stage " 1109 "%d, but we want stage %d", icp->conn_oid, 1110 pdu_next_stage, icp->conn_next_stage); 1111 return (ISCSI_STATUS_PROTOCOL_ERROR); 1112 } 1113 } 1114 1115 if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) { 1116 if (iscsiAuthClientRecvBegin(auth_client) != 1117 iscsiAuthStatusNoError) { 1118 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 1119 "authentication receive failed", icp->conn_oid); 1120 return (ISCSI_STATUS_INTERNAL_ERROR); 1121 } 1122 1123 if (iscsiAuthClientRecvTransitBit(auth_client, 1124 transit) != iscsiAuthStatusNoError) { 1125 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 1126 "authentication transmit failed", icp->conn_oid); 1127 return (ISCSI_STATUS_INTERNAL_ERROR); 1128 } 1129 } 1130 1131 /* 1132 * scan the text data 1133 */ 1134 more_text: 1135 while (text && (text < end)) { 1136 char *value = NULL; 1137 char *value_end = NULL; 1138 1139 /* 1140 * skip any NULs separating each text key=value pair 1141 */ 1142 while ((text < end) && (*text == '\0')) { 1143 text++; 1144 } 1145 if (text >= end) { 1146 break; 1147 } 1148 1149 /* 1150 * handle keys appropriate for each stage 1151 */ 1152 switch (icp->conn_current_stage) { 1153 case ISCSI_SECURITY_NEGOTIATION_STAGE: 1154 /* 1155 * a few keys are possible in Security stage 1156 * * which the auth code doesn't care about, 1157 * * but which we might want to see, or at 1158 * * least not choke on. 1159 */ 1160 if (iscsi_find_key_value("TargetAlias", 1161 text, end, &value, &value_end)) { 1162 isp->sess_alias_length = 1163 sizeof (isp->sess_alias) - 1; 1164 1165 if ((value_end - value) < 1166 isp->sess_alias_length) { 1167 isp->sess_alias_length = 1168 value_end - value; 1169 } 1170 1171 bcopy(value, isp->sess_alias, 1172 isp->sess_alias_length); 1173 isp->sess_alias[isp->sess_alias_length + 1] = 1174 '\0'; 1175 text = value_end; 1176 1177 } else if (iscsi_find_key_value("TargetAddress", 1178 text, end, &value, &value_end)) { 1179 if (!ISCSI_SUCCESS(iscsi_update_address( 1180 icp, value))) { 1181 cmn_err(CE_WARN, "iscsi connection(%u) " 1182 "login failed - login redirection " 1183 "invalid", icp->conn_oid); 1184 return (ISCSI_STATUS_PROTOCOL_ERROR); 1185 } 1186 text = value_end; 1187 } else if (iscsi_find_key_value("TargetPortalGroupTag", 1188 text, end, &value, &value_end)) { 1189 /* 1190 * We should have already obtained this via 1191 * discovery. We've already picked an isid, 1192 * so the most we can do is confirm we reached 1193 * the portal group we were expecting to. 1194 */ 1195 if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) { 1196 return (ISCSI_STATUS_PROTOCOL_ERROR); 1197 } 1198 if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) { 1199 if (tmp != isp->sess_tpgt_conf) { 1200 1201 cmn_err(CE_WARN, "iscsi connection(%u) login failed - target " 1202 "protocol group tag mismatch, expected %d, received %lu", 1203 icp->conn_oid, isp->sess_tpgt_conf, tmp); 1204 return (ISCSI_STATUS_PROTOCOL_ERROR); 1205 1206 } 1207 } 1208 isp->sess_tpgt_nego = (int)tmp; 1209 text = value_end; 1210 } else { 1211 /* 1212 * any key we don't recognize either goes 1213 * to the auth code, or we choke on it 1214 */ 1215 int keytype = iscsiAuthKeyTypeNone; 1216 1217 while (iscsiAuthClientGetNextKeyType( 1218 &keytype) == iscsiAuthStatusNoError) { 1219 1220 char *key = 1221 (char *)iscsiAuthClientGetKeyName( 1222 keytype); 1223 1224 if ((key) && 1225 (iscsi_find_key_value(key, 1226 text, end, &value, &value_end))) { 1227 1228 if (iscsiAuthClientRecvKeyValue 1229 (auth_client, keytype, 1230 value) != 1231 iscsiAuthStatusNoError) { 1232 1233 cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't accept " 1234 "%s in security stage", icp->conn_oid, text); 1235 return (ISCSI_STATUS_NEGO_FAIL); 1236 1237 } 1238 text = value_end; 1239 goto more_text; 1240 } 1241 } 1242 1243 cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't except " 1244 "%s in security stage", icp->conn_oid, text); 1245 1246 return (ISCSI_STATUS_NEGO_FAIL); 1247 } 1248 break; 1249 case ISCSI_OP_PARMS_NEGOTIATION_STAGE: 1250 if (iscsi_find_key_value("TargetAlias", text, 1251 end, &value, &value_end)) { 1252 isp->sess_alias_length = 1253 sizeof (isp->sess_alias) - 1; 1254 1255 if ((value_end - value) < 1256 isp->sess_alias_length) { 1257 isp->sess_alias_length = 1258 value_end - value; 1259 } 1260 1261 bcopy(value, isp->sess_alias, 1262 isp->sess_alias_length); 1263 isp->sess_alias[isp->sess_alias_length + 1] = 1264 '\0'; 1265 text = value_end; 1266 1267 } else if (iscsi_find_key_value("TargetAddress", 1268 text, end, &value, &value_end)) { 1269 if (!ISCSI_SUCCESS(iscsi_update_address( 1270 icp, value))) { 1271 1272 cmn_err(CE_WARN, "iscsi connection(%u) login failed - login " 1273 "redirection invalid", icp->conn_oid); 1274 1275 return (ISCSI_STATUS_PROTOCOL_ERROR); 1276 } 1277 text = value_end; 1278 } else if (iscsi_find_key_value("TargetPortalGroupTag", 1279 text, end, &value, &value_end)) { 1280 /* 1281 * We should have already obtained this via 1282 * discovery. We've already picked an isid, 1283 * so the most we can do is confirm we reached 1284 * the portal group we were expecting to. 1285 */ 1286 if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) { 1287 return (ISCSI_STATUS_PROTOCOL_ERROR); 1288 } 1289 if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) { 1290 if (tmp != isp->sess_tpgt_conf) { 1291 1292 cmn_err(CE_WARN, "iscsi connection(%u) login failed - target portal " 1293 "tag mismatch, expected:%d received:%lu", icp->conn_oid, 1294 isp->sess_tpgt_conf, tmp); 1295 return (ISCSI_STATUS_PROTOCOL_ERROR); 1296 1297 } 1298 } 1299 isp->sess_tpgt_nego = (int)tmp; 1300 text = value_end; 1301 1302 } else if (iscsi_find_key_value("InitialR2T", 1303 text, end, &value, &value_end)) { 1304 1305 /* 1306 * iSCSI RFC section 12.10 states that 1307 * InitialR2T is Irrelevant for a 1308 * discovery session. 1309 */ 1310 if (isp->sess_type == 1311 ISCSI_SESS_TYPE_DISCOVERY) { 1312 /* EMPTY */ 1313 } else if (value == NULL) { 1314 cmn_err(CE_WARN, "iscsi connection(%u) " 1315 "login failed - InitialR2T is " 1316 "invalid - protocol error", 1317 icp->conn_oid); 1318 return (ISCSI_STATUS_PROTOCOL_ERROR); 1319 } else if (strcmp(value, "Yes") == 0) { 1320 icp->conn_params.initial_r2t = B_TRUE; 1321 } else if (strcmp(value, "No") == 0) { 1322 icp->conn_params.initial_r2t = B_FALSE; 1323 } else { 1324 cmn_err(CE_WARN, "iscsi connection(%u) " 1325 "login failed - InitialR2T is " 1326 "invalid - protocol error", 1327 icp->conn_oid); 1328 return (ISCSI_STATUS_PROTOCOL_ERROR); 1329 } 1330 text = value_end; 1331 1332 } else if (iscsi_find_key_value("ImmediateData", 1333 text, end, &value, &value_end)) { 1334 1335 /* 1336 * iSCSI RFC section 12.11 states that 1337 * ImmediateData is Irrelevant for a 1338 * discovery session. 1339 */ 1340 if (isp->sess_type == 1341 ISCSI_SESS_TYPE_DISCOVERY) { 1342 /* EMPTY */ 1343 } else if (value == NULL) { 1344 cmn_err(CE_WARN, "iscsi connection(%u) " 1345 "login failed - ImmediateData is " 1346 "invalid - protocol error", 1347 icp->conn_oid); 1348 return (ISCSI_STATUS_PROTOCOL_ERROR); 1349 } else if (strcmp(value, "Yes") == 0) { 1350 icp->conn_params.immediate_data = 1; 1351 } else if (strcmp(value, "No") == 0) { 1352 icp->conn_params.immediate_data = 0; 1353 } else { 1354 cmn_err(CE_WARN, "iscsi connection(%u) " 1355 "login failed - ImmediateData is " 1356 "invalid - protocol error", 1357 icp->conn_oid); 1358 return (ISCSI_STATUS_PROTOCOL_ERROR); 1359 } 1360 text = value_end; 1361 1362 } else if (iscsi_find_key_value( 1363 "MaxRecvDataSegmentLength", text, end, 1364 &value, &value_end)) { 1365 1366 if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) { 1367 cmn_err(CE_WARN, "iscsi connection(%u) " 1368 "login failed - MaxRecvDataSegment" 1369 "Length is invalid - protocol " 1370 "error", icp->conn_oid); 1371 return (ISCSI_STATUS_NEGO_FAIL); 1372 } 1373 icp->conn_params.max_recv_data_seg_len = 1374 icp->conn_params.max_xmit_data_seg_len = 1375 (int)tmp; 1376 1377 text = value_end; 1378 } else if (iscsi_find_key_value("FirstBurstLength", 1379 text, end, &value, &value_end)) { 1380 1381 /* 1382 * iSCSI RFC section 12.14 states that 1383 * FirstBurstLength is Irrelevant if 1384 * InitialR2T=Yes and ImmediateData=No 1385 * or is this is a discovery session. 1386 */ 1387 if ((isp->sess_type == 1388 ISCSI_SESS_TYPE_DISCOVERY)) { 1389 /* EMPTY */ 1390 } else if (value && 1391 (strcmp(value, "Irrelevant") == 0)) { 1392 /* irrelevant */ 1393 fbl_irrelevant = B_TRUE; 1394 } else if (ddi_strtoul( 1395 value, &tmpe, 0, &tmp) != 0) { 1396 /* bad value */ 1397 cmn_err(CE_WARN, "iscsi connection(%u) " 1398 "login failed - FirstBurstLength" 1399 "is invalid - protocol error", 1400 icp->conn_oid); 1401 return (ISCSI_STATUS_PROTOCOL_ERROR); 1402 } else { 1403 /* good value */ 1404 icp->conn_params.first_burst_length = 1405 (int)tmp; 1406 } 1407 text = value_end; 1408 } else if (iscsi_find_key_value("MaxBurstLength", 1409 text, end, &value, &value_end)) { 1410 /* 1411 * iSCSI RFC section 12.13 states that 1412 * MaxBurstLength is Irrelevant for a 1413 * discovery session. 1414 */ 1415 if (isp->sess_type == 1416 ISCSI_SESS_TYPE_DISCOVERY) { 1417 /* EMPTY */ 1418 } else if (ddi_strtoul( 1419 value, &tmpe, 0, &tmp) != 0) { 1420 cmn_err(CE_WARN, "iscsi connection(%u) " 1421 "login failed - MaxBurstLength" 1422 "is invalid - protocol error", 1423 icp->conn_oid); 1424 return (ISCSI_STATUS_PROTOCOL_ERROR); 1425 } else { 1426 icp->conn_params.max_burst_length = 1427 (int)tmp; 1428 } 1429 1430 text = value_end; 1431 1432 } else if (iscsi_find_key_value("HeaderDigest", 1433 text, end, &value, &value_end)) { 1434 1435 if (strcmp(value, "None") == 0) { 1436 if (icp->conn_params.header_digest != 1437 ISCSI_DIGEST_CRC32C) { 1438 icp->conn_params.header_digest = 1439 ISCSI_DIGEST_NONE; 1440 } else { 1441 cmn_err(CE_WARN, "iscsi " 1442 "connection(%u) login " 1443 "failed - HeaderDigest=" 1444 "CRC32 is required, can't " 1445 "accept %s", 1446 icp->conn_oid, text); 1447 return (ISCSI_STATUS_NEGO_FAIL); 1448 } 1449 } else if (strcmp(value, "CRC32C") == 0) { 1450 if (icp->conn_params.header_digest != 1451 ISCSI_DIGEST_NONE) { 1452 icp->conn_params.header_digest = 1453 ISCSI_DIGEST_CRC32C; 1454 } else { 1455 cmn_err(CE_WARN, "iscsi " 1456 "connection(%u) login " 1457 "failed - HeaderDigest=" 1458 "None is required, can't " 1459 "accept %s", 1460 icp->conn_oid, text); 1461 return (ISCSI_STATUS_NEGO_FAIL); 1462 } 1463 } else { 1464 cmn_err(CE_WARN, "iscsi connection(%u) " 1465 "login failed - HeaderDigest " 1466 "can't accept %s", icp->conn_oid, 1467 text); 1468 return (ISCSI_STATUS_NEGO_FAIL); 1469 } 1470 text = value_end; 1471 } else if (iscsi_find_key_value("DataDigest", text, 1472 end, &value, &value_end)) { 1473 1474 if (strcmp(value, "None") == 0) { 1475 if (icp->conn_params.data_digest != 1476 ISCSI_DIGEST_CRC32C) { 1477 icp->conn_params.data_digest = 1478 ISCSI_DIGEST_NONE; 1479 } else { 1480 cmn_err(CE_WARN, "iscsi " 1481 "connection(%u) login " 1482 "failed - DataDigest=" 1483 "CRC32C is required, " 1484 "can't accept %s", 1485 icp->conn_oid, text); 1486 return (ISCSI_STATUS_NEGO_FAIL); 1487 } 1488 } else if (strcmp(value, "CRC32C") == 0) { 1489 if (icp->conn_params.data_digest != 1490 ISCSI_DIGEST_NONE) { 1491 icp->conn_params.data_digest = 1492 ISCSI_DIGEST_CRC32C; 1493 } else { 1494 cmn_err(CE_WARN, "iscsi " 1495 "connection(%u) login " 1496 "failed - DataDigest=None " 1497 "is required, can't " 1498 "accept %s", 1499 icp->conn_oid, text); 1500 return (ISCSI_STATUS_NEGO_FAIL); 1501 } 1502 } else { 1503 cmn_err(CE_WARN, "iscsi connection(%u) " 1504 "login failed - can't accept %s", 1505 icp->conn_oid, text); 1506 return (ISCSI_STATUS_NEGO_FAIL); 1507 } 1508 text = value_end; 1509 1510 } else if (iscsi_find_key_value("DefaultTime2Wait", 1511 text, end, &value, &value_end)) { 1512 1513 if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) { 1514 cmn_err(CE_WARN, "iscsi connection(%u) " 1515 "login failed - DefaultTime2Wait " 1516 "is invalid - protocol error", 1517 icp->conn_oid); 1518 return (ISCSI_STATUS_PROTOCOL_ERROR); 1519 } 1520 icp->conn_params.default_time_to_wait = 1521 (int)tmp; 1522 1523 text = value_end; 1524 1525 } else if (iscsi_find_key_value("DefaultTime2Retain", 1526 text, end, &value, &value_end)) { 1527 1528 if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) { 1529 cmn_err(CE_WARN, "iscsi connection(%u) " 1530 "login failed - DefaultTime2Retain " 1531 "is invalid - protocol error", 1532 icp->conn_oid); 1533 return (ISCSI_STATUS_PROTOCOL_ERROR); 1534 } 1535 icp->conn_params.default_time_to_retain = 1536 (int)tmp; 1537 1538 text = value_end; 1539 1540 } else if (iscsi_find_key_value("OFMarker", text, 1541 end, &value, &value_end)) { 1542 1543 /* 1544 * result function is AND, target must 1545 * honor our No 1546 */ 1547 text = value_end; 1548 1549 } else if (iscsi_find_key_value("OFMarkInt", text, 1550 end, &value, &value_end)) { 1551 1552 /* 1553 * we don't do markers, so we don't care 1554 */ 1555 text = value_end; 1556 1557 } else if (iscsi_find_key_value("IFMarker", text, 1558 end, &value, &value_end)) { 1559 1560 /* 1561 * result function is AND, target must 1562 * honor our No 1563 */ 1564 text = value_end; 1565 1566 } else if (iscsi_find_key_value("IFMarkInt", text, 1567 end, &value, &value_end)) { 1568 1569 /* 1570 * we don't do markers, so we don't care 1571 */ 1572 text = value_end; 1573 1574 } else if (iscsi_find_key_value("DataPDUInOrder", 1575 text, end, &value, &value_end)) { 1576 1577 /* 1578 * iSCSI RFC section 12.18 states that 1579 * DataPDUInOrder is Irrelevant for a 1580 * discovery session. 1581 */ 1582 if (isp->sess_type == 1583 ISCSI_SESS_TYPE_DISCOVERY) { 1584 /* EMPTY */ 1585 } else if (value == NULL) { 1586 cmn_err(CE_WARN, "iscsi connection(%u) " 1587 "login failed - InitialR2T is " 1588 "invalid - protocol error", 1589 icp->conn_oid); 1590 return (ISCSI_STATUS_PROTOCOL_ERROR); 1591 } else if (strcmp(value, "Yes") == 0) { 1592 icp->conn_params.data_pdu_in_order = 1593 B_TRUE; 1594 } else if (strcmp(value, "No") == 0) { 1595 icp->conn_params.data_pdu_in_order = 1596 B_FALSE; 1597 } else { 1598 cmn_err(CE_WARN, "iscsi connection(%u) " 1599 "login failed - InitialR2T is " 1600 "invalid - protocol error", 1601 icp->conn_oid); 1602 return (ISCSI_STATUS_PROTOCOL_ERROR); 1603 } 1604 text = value_end; 1605 1606 } else if (iscsi_find_key_value("DataSequenceInOrder", 1607 text, end, &value, &value_end)) { 1608 1609 /* 1610 * iSCSI RFC section 12.19 states that 1611 * DataSequenceInOrder is Irrelevant for a 1612 * discovery session. 1613 */ 1614 if (isp->sess_type == 1615 ISCSI_SESS_TYPE_DISCOVERY) { 1616 /* EMPTY */ 1617 } else if (value == NULL) { 1618 cmn_err(CE_WARN, "iscsi connection(%u) " 1619 "login failed - InitialR2T is " 1620 "invalid - protocol error", 1621 icp->conn_oid); 1622 return (ISCSI_STATUS_PROTOCOL_ERROR); 1623 } else if (strcmp(value, "Yes") == 0) { 1624 icp->conn_params. 1625 data_sequence_in_order = B_TRUE; 1626 } else if (strcmp(value, "No") == 0) { 1627 icp->conn_params. 1628 data_sequence_in_order = B_FALSE; 1629 } else { 1630 cmn_err(CE_WARN, "iscsi connection(%u) " 1631 "login failed - InitialR2T is " 1632 "invalid - protocol error", 1633 icp->conn_oid); 1634 return (ISCSI_STATUS_PROTOCOL_ERROR); 1635 } 1636 text = value_end; 1637 1638 } else if (iscsi_find_key_value("MaxOutstandingR2T", 1639 text, end, &value, &value_end)) { 1640 1641 /* 1642 * iSCSI RFC section 12.17 states that 1643 * MaxOutstandingR2T is Irrelevant for a 1644 * discovery session. 1645 */ 1646 if (isp->sess_type == 1647 ISCSI_SESS_TYPE_DISCOVERY) { 1648 /* EMPTY */ 1649 } else if (strcmp(value, "1")) { 1650 cmn_err(CE_WARN, "iscsi connection(%u) " 1651 "login failed - can't accept " 1652 "MaxOutstandingR2T %s", 1653 icp->conn_oid, value); 1654 return (ISCSI_STATUS_NEGO_FAIL); 1655 } 1656 text = value_end; 1657 1658 } else if (iscsi_find_key_value("MaxConnections", 1659 text, end, &value, &value_end)) { 1660 1661 /* 1662 * iSCSI RFC section 12.2 states that 1663 * MaxConnections is Irrelevant for a 1664 * discovery session. 1665 */ 1666 if (isp->sess_type == 1667 ISCSI_SESS_TYPE_DISCOVERY) { 1668 /* EMPTY */ 1669 } else if (strcmp(value, "1")) { 1670 cmn_err(CE_WARN, "iscsi connection(%u) " 1671 "login failed - can't accept " 1672 "MaxConnections %s", 1673 icp->conn_oid, value); 1674 return (ISCSI_STATUS_NEGO_FAIL); 1675 } 1676 text = value_end; 1677 1678 } else if (iscsi_find_key_value("ErrorRecoveryLevel", 1679 text, end, &value, &value_end)) { 1680 1681 if (strcmp(value, "0")) { 1682 1683 cmn_err(CE_WARN, "iscsi connection(%u) " 1684 "login failed - can't accept " 1685 "ErrorRecoveryLevel %s", 1686 icp->conn_oid, value); 1687 return (ISCSI_STATUS_NEGO_FAIL); 1688 } 1689 text = value_end; 1690 1691 } else { 1692 cmn_err(CE_WARN, "iscsi connection(%u) " 1693 "login failed - ignoring login " 1694 "parameter %s", icp->conn_oid, value); 1695 text = value_end; 1696 } 1697 break; 1698 default: 1699 return (ISCSI_STATUS_INTERNAL_ERROR); 1700 } 1701 } 1702 1703 /* 1704 * iSCSI RFC section 12.14 states that 1705 * FirstBurstLength is Irrelevant if 1706 * InitialR2T=Yes and ImmediateData=No. 1707 * This is a final check to make sure 1708 * the array didn't make a protocol 1709 * violation. 1710 */ 1711 if ((fbl_irrelevant == B_TRUE) && 1712 ((icp->conn_params.initial_r2t != B_TRUE) || 1713 (icp->conn_params.immediate_data != B_FALSE))) { 1714 cmn_err(CE_WARN, "iscsi connection(%u) login failed - " 1715 "FirstBurstLength=Irrelevant and (InitialR2T!=Yes or " 1716 "ImmediateData!=No) - protocol error", icp->conn_oid); 1717 return (ISCSI_STATUS_PROTOCOL_ERROR); 1718 } 1719 1720 if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) { 1721 switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback, 1722 (void *)isp, NULL)) { 1723 case iscsiAuthStatusContinue: 1724 /* 1725 * continue sending PDUs 1726 */ 1727 break; 1728 1729 case iscsiAuthStatusPass: 1730 break; 1731 1732 case iscsiAuthStatusInProgress: 1733 /* 1734 * this should only occur if we were authenticating the 1735 * target, which we don't do yet, so treat this as an 1736 * error. 1737 */ 1738 case iscsiAuthStatusNoError: 1739 /* 1740 * treat this as an error, since we should get a 1741 * different code 1742 */ 1743 case iscsiAuthStatusError: 1744 case iscsiAuthStatusFail: 1745 default: 1746 debug_status = 0; 1747 1748 if (iscsiAuthClientGetDebugStatus(auth_client, 1749 &debug_status) != iscsiAuthStatusNoError) { 1750 1751 cmn_err(CE_WARN, "iscsi connection(%u) login " 1752 "failed - authentication failed with " 1753 "target (%s)", icp->conn_oid, 1754 iscsiAuthClientDebugStatusToText( 1755 debug_status)); 1756 1757 } else { 1758 1759 cmn_err(CE_WARN, "iscsi connection(%u) login " 1760 "failed - authentication failed with " 1761 "target", icp->conn_oid); 1762 1763 } 1764 return (ISCSI_STATUS_AUTHENTICATION_FAILED); 1765 } 1766 } 1767 1768 /* 1769 * record some of the PDU fields for later use 1770 */ 1771 isp->sess_tsid = ntohs(ilrhp->tsid); 1772 isp->sess_expcmdsn = ntohl(ilrhp->expcmdsn); 1773 isp->sess_maxcmdsn = ntohl(ilrhp->maxcmdsn); 1774 if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 1775 icp->conn_expstatsn = ntohl(ilrhp->statsn) + 1; 1776 } 1777 1778 if (transit) { 1779 /* 1780 * advance to the next stage 1781 */ 1782 icp->conn_partial_response = 0; 1783 icp->conn_current_stage = 1784 ilrhp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; 1785 } else { 1786 /* 1787 * we got a partial response, don't advance, more 1788 * negotiation to do 1789 */ 1790 icp->conn_partial_response = 1; 1791 } 1792 1793 /* 1794 * this PDU is ok, though the login process 1795 * may not be done yet 1796 */ 1797 return (ISCSI_STATUS_SUCCESS); 1798 } 1799 1800 /* 1801 * iscsi_add_text - caller is assumed to be well-behaved and passing NUL 1802 * terminated strings 1803 */ 1804 int 1805 iscsi_add_text(idm_pdu_t *text_pdu, int max_data_length, 1806 char *param, char *value) 1807 { 1808 int param_len = 0; 1809 int value_len = 0; 1810 int length = 0; 1811 int pdu_length = 0; 1812 char *text = NULL; 1813 char *end = NULL; 1814 1815 ASSERT(text_pdu != NULL); 1816 ASSERT(param != NULL); 1817 ASSERT(value != NULL); 1818 1819 param_len = strlen(param); 1820 value_len = strlen(value); 1821 /* param, separator, value, and trailing NULL */ 1822 length = param_len + 1 + value_len + 1; 1823 pdu_length = text_pdu->isp_datalen; 1824 text = (char *)text_pdu->isp_data + pdu_length; 1825 end = (char *)text_pdu->isp_data + max_data_length; 1826 pdu_length += length; 1827 1828 if (text + length >= end) { 1829 return (0); 1830 } 1831 1832 /* param */ 1833 (void) strncpy(text, param, param_len); 1834 text += param_len; 1835 1836 /* separator */ 1837 *text++ = ISCSI_TEXT_SEPARATOR; 1838 1839 /* value */ 1840 (void) strncpy(text, value, value_len); 1841 text += value_len; 1842 1843 /* NULL */ 1844 *text++ = '\0'; 1845 1846 /* update the length in the PDU header */ 1847 text_pdu->isp_datalen = pdu_length; 1848 hton24(text_pdu->isp_hdr->dlength, pdu_length); 1849 1850 return (1); 1851 } 1852 1853 /* 1854 * iscsi_get_next_text - get the next line of text from the given data 1855 * buffer. This function searches from the address given for the 1856 * curr_text parameter. If curr_text_parameter is NULL return first 1857 * line in buffer. The return value is the address of the next line 1858 * based upon where curr_text is located. 1859 * 1860 */ 1861 char * 1862 iscsi_get_next_text(char *data, int max_data_length, char *curr_text) 1863 { 1864 char *curr_data; 1865 1866 ASSERT(data != NULL); 1867 1868 /* check if any data exists, if not return */ 1869 if (max_data_length == 0) { 1870 return (NULL); 1871 } 1872 1873 /* handle first call to this function */ 1874 if (curr_text == NULL) { 1875 return (data); 1876 } 1877 1878 /* move to next text string */ 1879 curr_data = curr_text; 1880 while ((curr_data < (data + max_data_length)) && *curr_data) { 1881 curr_data++; 1882 } 1883 curr_data++; /* go past the NULL to the next entry */ 1884 1885 /* check whether data end reached */ 1886 if (curr_data >= (data + max_data_length)) { 1887 return (NULL); 1888 } 1889 1890 return (curr_data); 1891 } 1892 1893 1894 /* 1895 * iscsi_find_key_value - 1896 * 1897 */ 1898 static int 1899 iscsi_find_key_value(char *param, char *ihp, char *pdu_end, 1900 char **value_start, char **value_end) 1901 { 1902 char *str = param; 1903 char *text = ihp; 1904 char *value = NULL; 1905 1906 if (value_start) 1907 *value_start = NULL; 1908 if (value_end) 1909 *value_end = NULL; 1910 1911 /* 1912 * make sure they contain the same bytes 1913 */ 1914 while (*str) { 1915 if (text >= pdu_end) { 1916 return (0); 1917 } 1918 if (*text == '\0') { 1919 return (0); 1920 } 1921 if (*str != *text) { 1922 return (0); 1923 } 1924 str++; 1925 text++; 1926 } 1927 1928 if ((text >= pdu_end) || 1929 (*text == '\0') || 1930 (*text != ISCSI_TEXT_SEPARATOR)) { 1931 return (0); 1932 } 1933 1934 /* 1935 * find the value 1936 */ 1937 value = text + 1; 1938 1939 /* 1940 * find the end of the value 1941 */ 1942 while ((text < pdu_end) && (*text)) 1943 text++; 1944 1945 if (value_start) 1946 *value_start = value; 1947 if (value_end) 1948 *value_end = text; 1949 1950 return (1); 1951 } 1952 1953 1954 /* 1955 * iscsi_update_address - This function is used on a login redirection. 1956 * During the login redirection we are asked to switch to an IP address 1957 * port different than the one we were logging into. 1958 */ 1959 static iscsi_status_t 1960 iscsi_update_address(iscsi_conn_t *icp, char *in) 1961 { 1962 char *addr_str, *port_str, *tpgt_str; 1963 int type; 1964 struct hostent *hptr; 1965 unsigned long tmp; 1966 int error_num; 1967 int port; 1968 1969 ASSERT(icp != NULL); 1970 ASSERT(in != NULL); 1971 1972 /* parse login redirection response */ 1973 if (parse_addr_port_tpgt(in, &addr_str, &type, 1974 &port_str, &tpgt_str) == B_FALSE) { 1975 return (ISCSI_STATUS_PROTOCOL_ERROR); 1976 } 1977 1978 /* convert addr_str */ 1979 hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num); 1980 if (!hptr) { 1981 return (ISCSI_STATUS_PROTOCOL_ERROR); 1982 } 1983 1984 /* convert port_str */ 1985 if (port_str != NULL) { 1986 (void) ddi_strtoul(port_str, NULL, 0, &tmp); 1987 port = (int)tmp; 1988 } else { 1989 port = ISCSI_LISTEN_PORT; 1990 } 1991 1992 iscsid_addr_to_sockaddr(hptr->h_length, *hptr->h_addr_list, 1993 port, &icp->conn_curr_addr.sin); 1994 1995 kfreehostent(hptr); 1996 return (ISCSI_STATUS_SUCCESS); 1997 } 1998 1999 void 2000 iscsi_login_update_state(iscsi_conn_t *icp, iscsi_login_state_t next_state) 2001 { 2002 mutex_enter(&icp->conn_login_mutex); 2003 (void) iscsi_login_update_state_locked(icp, next_state); 2004 mutex_exit(&icp->conn_login_mutex); 2005 } 2006 2007 void 2008 iscsi_login_update_state_locked(iscsi_conn_t *icp, 2009 iscsi_login_state_t next_state) 2010 { 2011 ASSERT(mutex_owned(&icp->conn_login_mutex)); 2012 next_state = (next_state > LOGIN_MAX) ? LOGIN_MAX : next_state; 2013 idm_sm_audit_state_change(&icp->conn_state_audit, 2014 SAS_ISCSI_LOGIN, icp->conn_login_state, next_state); 2015 2016 ISCSI_LOGIN_LOG(CE_NOTE, "iscsi_login_update_state conn %p %d -> %d", 2017 (void *)icp, icp->conn_login_state, next_state); 2018 2019 icp->conn_login_state = next_state; 2020 cv_broadcast(&icp->conn_login_cv); 2021 } 2022 2023 2024 2025 /* 2026 * iscsi_null_callback - This callback may be used under certain 2027 * conditions when authenticating a target, but I'm not sure what 2028 * we need to do here. 2029 */ 2030 /* ARGSUSED */ 2031 static void 2032 iscsi_null_callback(void *user_handle, void *message_handle, int auth_status) 2033 { 2034 } 2035 2036 2037 /* 2038 * iscsi_login_failure_str - 2039 * 2040 */ 2041 static char * 2042 iscsi_login_failure_str(uchar_t status_class, uchar_t status_detail) 2043 { 2044 switch (status_class) { 2045 case 0x00: 2046 switch (status_detail) { 2047 case 0x00: 2048 return ("Login is proceeding okay."); 2049 default: 2050 break; 2051 } 2052 case 0x01: 2053 switch (status_detail) { 2054 case 0x01: 2055 return ("Requested ITN has moved temporarily to " 2056 "the address provided."); 2057 case 0x02: 2058 return ("Requested ITN has moved permanently to " 2059 "the address provided."); 2060 default: 2061 break; 2062 } 2063 case 0x02: 2064 switch (status_detail) { 2065 case 0x00: 2066 return ("Miscellaneous iSCSI initiator errors."); 2067 case 0x01: 2068 return ("Initiator could not be successfully " 2069 "authenticated."); 2070 case 0x02: 2071 return ("Initiator is not allowed access to the " 2072 "given target."); 2073 case 0x03: 2074 return ("Requested ITN does not exist at this " 2075 "address."); 2076 case 0x04: 2077 return ("Requested ITN has been removed and no " 2078 "forwarding address is provided."); 2079 case 0x05: 2080 return ("Requested iSCSI version range is not " 2081 "supported by the target."); 2082 case 0x06: 2083 return ("No more connections can be accepted on " 2084 "this Session ID (SSID)."); 2085 case 0x07: 2086 return ("Missing parameters (e.g., iSCSI initiator " 2087 "and/or target name)."); 2088 case 0x08: 2089 return ("Target does not support session spanning " 2090 "to this connection (address)."); 2091 case 0x09: 2092 return ("Target does not support this type of " 2093 "session or not from this initiator."); 2094 case 0x0A: 2095 return ("Attempt to add a connection to a " 2096 "nonexistent session."); 2097 case 0x0B: 2098 return ("Invalid request type during login."); 2099 default: 2100 break; 2101 } 2102 case 0x03: 2103 switch (status_detail) { 2104 case 0x00: 2105 return ("Target hardware or software error."); 2106 case 0x01: 2107 return ("iSCSI service or target is not currently " 2108 "operational."); 2109 case 0x02: 2110 return ("Target has insufficient session, connection " 2111 "or other resources."); 2112 default: 2113 break; 2114 } 2115 } 2116 return ("Unknown login response received."); 2117 } 2118 2119 2120 /* 2121 * iscsi_login_connect - 2122 */ 2123 static iscsi_status_t 2124 iscsi_login_connect(iscsi_conn_t *icp) 2125 { 2126 iscsi_hba_t *ihp; 2127 iscsi_sess_t *isp; 2128 struct sockaddr *addr; 2129 idm_conn_req_t cr; 2130 idm_status_t rval; 2131 clock_t lbolt; 2132 2133 ASSERT(icp != NULL); 2134 isp = icp->conn_sess; 2135 ASSERT(isp != NULL); 2136 ihp = isp->sess_hba; 2137 ASSERT(ihp != NULL); 2138 addr = &icp->conn_curr_addr.sin; 2139 2140 /* Make sure that scope_id is zero if it is an IPv6 address */ 2141 if (addr->sa_family == AF_INET6) { 2142 ((struct sockaddr_in6 *)addr)->sin6_scope_id = 0; 2143 } 2144 2145 /* delay the connect process if required */ 2146 lbolt = ddi_get_lbolt(); 2147 if (lbolt < icp->conn_login_min) { 2148 if (icp->conn_login_max < icp->conn_login_min) { 2149 delay(icp->conn_login_max - lbolt); 2150 } else { 2151 delay(icp->conn_login_min - lbolt); 2152 } 2153 } 2154 2155 /* Create IDM connection context */ 2156 cr.cr_domain = addr->sa_family; 2157 cr.cr_type = SOCK_STREAM; 2158 cr.cr_protocol = 0; 2159 cr.cr_bound = icp->conn_bound; 2160 cr.cr_li = icp->conn_sess->sess_hba->hba_li; 2161 cr.icr_conn_ops.icb_rx_misc = &iscsi_rx_misc_pdu; 2162 cr.icr_conn_ops.icb_rx_error = &iscsi_rx_error_pdu; 2163 cr.icr_conn_ops.icb_rx_scsi_rsp = &iscsi_rx_scsi_rsp; 2164 cr.icr_conn_ops.icb_client_notify = &iscsi_client_notify; 2165 cr.icr_conn_ops.icb_build_hdr = &iscsi_build_hdr; 2166 cr.icr_conn_ops.icb_task_aborted = &iscsi_task_aborted; 2167 bcopy(addr, &cr.cr_ini_dst_addr, 2168 sizeof (cr.cr_ini_dst_addr)); 2169 bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr, 2170 sizeof (cr.cr_bound_addr)); 2171 if (isp->sess_boot == B_TRUE) { 2172 cr.cr_boot_conn = B_TRUE; 2173 } else { 2174 cr.cr_boot_conn = B_FALSE; 2175 } 2176 2177 /* 2178 * Allocate IDM connection context 2179 */ 2180 rval = idm_ini_conn_create(&cr, &icp->conn_ic); 2181 if (rval != IDM_STATUS_SUCCESS) { 2182 return (ISCSI_STATUS_LOGIN_FAILED); 2183 } 2184 2185 icp->conn_ic->ic_handle = icp; 2186 2187 /* 2188 * About to initiate connect, reset login state. 2189 */ 2190 iscsi_login_update_state(icp, LOGIN_START); 2191 2192 /* 2193 * Make sure the connection doesn't go away until we are done with it. 2194 * This hold will prevent us from receiving a CN_CONNECT_DESTROY 2195 * notification on this connection until we are ready. 2196 */ 2197 idm_conn_hold(icp->conn_ic); 2198 2199 /* 2200 * When iSCSI initiator to target IO timeout or connection failure 2201 * Connection retry is needed for normal operational session. 2202 */ 2203 if ((icp->conn_sess->sess_type == ISCSI_SESS_TYPE_NORMAL) && 2204 ((icp->conn_state == ISCSI_CONN_STATE_FAILED) || 2205 (icp->conn_state == ISCSI_CONN_STATE_POLLING))) { 2206 icp->conn_ic->ic_conn_params.nonblock_socket = B_TRUE; 2207 icp->conn_ic->ic_conn_params.conn_login_max = 2208 icp->conn_login_max; 2209 if (icp->conn_state == ISCSI_CONN_STATE_POLLING) { 2210 icp->conn_ic->ic_conn_params.conn_login_interval = 2211 icp->conn_tunable_params.polling_login_delay; 2212 } else { 2213 icp->conn_ic->ic_conn_params.conn_login_interval = 2214 ISCSI_LOGIN_RETRY_DELAY; 2215 } 2216 2217 } else { 2218 icp->conn_ic->ic_conn_params.nonblock_socket = B_FALSE; 2219 icp->conn_ic->ic_conn_params.conn_login_max = 0; 2220 icp->conn_ic->ic_conn_params.conn_login_interval = 0; 2221 } 2222 /* 2223 * Attempt connection. Upon return we will either be ready to 2224 * login or disconnected. If idm_ini_conn_connect fails we 2225 * will eventually receive a CN_CONNECT_DESTROY at which point 2226 * we will destroy the connection allocated above (so there 2227 * is no need to explicitly free it here). 2228 */ 2229 rval = idm_ini_conn_connect(icp->conn_ic); 2230 2231 if (rval != IDM_STATUS_SUCCESS) { 2232 cmn_err(CE_NOTE, "iscsi connection(%u) unable to " 2233 "connect to target %s", icp->conn_oid, 2234 icp->conn_sess->sess_name); 2235 idm_conn_rele(icp->conn_ic); 2236 } 2237 2238 return (rval == IDM_STATUS_SUCCESS ? 2239 ISCSI_STATUS_SUCCESS : ISCSI_STATUS_INTERNAL_ERROR); 2240 } 2241 2242 /* 2243 * iscsi_login_disconnect 2244 */ 2245 static void 2246 iscsi_login_disconnect(iscsi_conn_t *icp) 2247 { 2248 /* Tell IDM to disconnect is if we are not already disconnect */ 2249 idm_ini_conn_disconnect_sync(icp->conn_ic); 2250 2251 /* 2252 * The function above may return before the CN_CONNECT_LOST 2253 * notification. Wait for it. 2254 */ 2255 mutex_enter(&icp->conn_state_mutex); 2256 while (icp->conn_state_idm_connected) 2257 cv_wait(&icp->conn_state_change, 2258 &icp->conn_state_mutex); 2259 mutex_exit(&icp->conn_state_mutex); 2260 } 2261 2262 /* 2263 * iscsi_notice_key_values - Create an nvlist containing the values 2264 * that have been negotiated for this connection and pass them down to 2265 * IDM so it can pick up any values that are important. 2266 */ 2267 static void 2268 iscsi_notice_key_values(iscsi_conn_t *icp) 2269 { 2270 nvlist_t *neg_nvl; 2271 int rc; 2272 2273 rc = nvlist_alloc(&neg_nvl, NV_UNIQUE_NAME, KM_SLEEP); 2274 ASSERT(rc == 0); 2275 2276 /* Only crc32c is supported so the digest logic is simple */ 2277 if (icp->conn_params.header_digest) { 2278 rc = nvlist_add_string(neg_nvl, "HeaderDigest", "crc32c"); 2279 } else { 2280 rc = nvlist_add_string(neg_nvl, "HeaderDigest", "none"); 2281 } 2282 ASSERT(rc == 0); 2283 2284 if (icp->conn_params.data_digest) { 2285 rc = nvlist_add_string(neg_nvl, "DataDigest", "crc32c"); 2286 } else { 2287 rc = nvlist_add_string(neg_nvl, "DataDigest", "none"); 2288 } 2289 ASSERT(rc == 0); 2290 2291 rc = nvlist_add_uint64(neg_nvl, "MaxRecvDataSegmentLength", 2292 (uint64_t)icp->conn_params.max_recv_data_seg_len); 2293 ASSERT(rc == 0); 2294 2295 rc = nvlist_add_uint64(neg_nvl, "MaxBurstLength", 2296 (uint64_t)icp->conn_params.max_burst_length); 2297 ASSERT(rc == 0); 2298 2299 rc = nvlist_add_uint64(neg_nvl, "MaxOutstandingR2T", 2300 (uint64_t)icp->conn_params.max_outstanding_r2t); 2301 ASSERT(rc == 0); 2302 2303 rc = nvlist_add_uint64(neg_nvl, "ErrorRecoveryLevel", 2304 (uint64_t)icp->conn_params.error_recovery_level); 2305 ASSERT(rc == 0); 2306 2307 rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Wait", 2308 (uint64_t)icp->conn_params.default_time_to_wait); 2309 ASSERT(rc == 0); 2310 2311 rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Retain", 2312 (uint64_t)icp->conn_params.default_time_to_retain); 2313 ASSERT(rc == 0); 2314 2315 /* Pass the list to IDM to examine, then free it */ 2316 idm_notice_key_values(icp->conn_ic, neg_nvl); 2317 nvlist_free(neg_nvl); 2318 } 2319