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