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