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