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