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