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