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