1a6d42e7dSPeter Dunlap /* 2a6d42e7dSPeter Dunlap * CDDL HEADER START 3a6d42e7dSPeter Dunlap * 4a6d42e7dSPeter Dunlap * The contents of this file are subject to the terms of the 5a6d42e7dSPeter Dunlap * Common Development and Distribution License (the "License"). 6a6d42e7dSPeter Dunlap * You may not use this file except in compliance with the License. 7a6d42e7dSPeter Dunlap * 8a6d42e7dSPeter Dunlap * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a6d42e7dSPeter Dunlap * or http://www.opensolaris.org/os/licensing. 10a6d42e7dSPeter Dunlap * See the License for the specific language governing permissions 11a6d42e7dSPeter Dunlap * and limitations under the License. 12a6d42e7dSPeter Dunlap * 13a6d42e7dSPeter Dunlap * When distributing Covered Code, include this CDDL HEADER in each 14a6d42e7dSPeter Dunlap * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a6d42e7dSPeter Dunlap * If applicable, add the following below this CDDL HEADER, with the 16a6d42e7dSPeter Dunlap * fields enclosed by brackets "[]" replaced with your own identifying 17a6d42e7dSPeter Dunlap * information: Portions Copyright [yyyy] [name of copyright owner] 18a6d42e7dSPeter Dunlap * 19a6d42e7dSPeter Dunlap * CDDL HEADER END 20a6d42e7dSPeter Dunlap */ 21483b029bSYuri Pankov 22a6d42e7dSPeter Dunlap /* 234558d122SViswanathan Kannappan * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 241ef61828SYuri Pankov * Copyright 2016 Nexenta Systems, Inc. 25a6d42e7dSPeter Dunlap */ 26a6d42e7dSPeter Dunlap 27a6d42e7dSPeter Dunlap #include <sys/cpuvar.h> 28a6d42e7dSPeter Dunlap #include <sys/types.h> 29a6d42e7dSPeter Dunlap #include <sys/conf.h> 30a6d42e7dSPeter Dunlap #include <sys/file.h> 31a6d42e7dSPeter Dunlap #include <sys/ddi.h> 32a6d42e7dSPeter Dunlap #include <sys/sunddi.h> 33a6d42e7dSPeter Dunlap #include <sys/modctl.h> 34716c1805SNattuvetty Bhavyan #include <sys/scsi/generic/persist.h> 351ef61828SYuri Pankov #include <sys/scsi/scsi_names.h> 36a6d42e7dSPeter Dunlap 37a6d42e7dSPeter Dunlap #include <sys/socket.h> 38a6d42e7dSPeter Dunlap #include <sys/strsubr.h> 39a6d42e7dSPeter Dunlap #include <sys/sysmacros.h> 40a6d42e7dSPeter Dunlap #include <sys/note.h> 41a6d42e7dSPeter Dunlap #include <sys/sdt.h> 421ef61828SYuri Pankov #include <sys/errno.h> 43a6d42e7dSPeter Dunlap 44a6d42e7dSPeter Dunlap #include <sys/stmf.h> 45a6d42e7dSPeter Dunlap #include <sys/stmf_ioctl.h> 46a6d42e7dSPeter Dunlap #include <sys/portif.h> 47a6d42e7dSPeter Dunlap #include <sys/idm/idm.h> 48a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h> 49a6d42e7dSPeter Dunlap 50a6d42e7dSPeter Dunlap #define ISCSIT_LOGIN_SM_STRINGS 514558d122SViswanathan Kannappan #include "iscsit.h" 524558d122SViswanathan Kannappan #include "iscsit_auth.h" 53a6d42e7dSPeter Dunlap 54a6d42e7dSPeter Dunlap typedef struct { 55a6d42e7dSPeter Dunlap list_node_t le_ctx_node; 56a6d42e7dSPeter Dunlap iscsit_login_event_t le_ctx_event; 57a6d42e7dSPeter Dunlap idm_pdu_t *le_pdu; 58a6d42e7dSPeter Dunlap } login_event_ctx_t; 59a6d42e7dSPeter Dunlap 60a6d42e7dSPeter Dunlap #ifndef TRUE 61a6d42e7dSPeter Dunlap #define TRUE B_TRUE 62a6d42e7dSPeter Dunlap #endif 63a6d42e7dSPeter Dunlap 64a6d42e7dSPeter Dunlap #ifndef FALSE 65a6d42e7dSPeter Dunlap #define FALSE B_FALSE 66a6d42e7dSPeter Dunlap #endif 67a6d42e7dSPeter Dunlap 68a6d42e7dSPeter Dunlap #define DEFAULT_RADIUS_PORT 1812 69a6d42e7dSPeter Dunlap 70a6d42e7dSPeter Dunlap static void 71a6d42e7dSPeter Dunlap login_sm_complete(void *ict_void); 72a6d42e7dSPeter Dunlap 73a6d42e7dSPeter Dunlap static void 74a6d42e7dSPeter Dunlap login_sm_event_dispatch(iscsit_conn_login_t *lsm, iscsit_conn_t *ict, 75a6d42e7dSPeter Dunlap login_event_ctx_t *ctx); 76a6d42e7dSPeter Dunlap 77a6d42e7dSPeter Dunlap static void 78a6d42e7dSPeter Dunlap login_sm_init(iscsit_conn_t *ict, login_event_ctx_t *ctx); 79a6d42e7dSPeter Dunlap 80a6d42e7dSPeter Dunlap static void 81a6d42e7dSPeter Dunlap login_sm_waiting(iscsit_conn_t *ict, login_event_ctx_t *ctx); 82a6d42e7dSPeter Dunlap 83a6d42e7dSPeter Dunlap static void 84a6d42e7dSPeter Dunlap login_sm_processing(iscsit_conn_t *ict, login_event_ctx_t *ctx); 85a6d42e7dSPeter Dunlap 86a6d42e7dSPeter Dunlap static void 87a6d42e7dSPeter Dunlap login_sm_responding(iscsit_conn_t *ict, login_event_ctx_t *ctx); 88a6d42e7dSPeter Dunlap 89a6d42e7dSPeter Dunlap static void 90a6d42e7dSPeter Dunlap login_sm_responded(iscsit_conn_t *ict, login_event_ctx_t *ctx); 91a6d42e7dSPeter Dunlap 92a6d42e7dSPeter Dunlap static void 93a6d42e7dSPeter Dunlap login_sm_ffp(iscsit_conn_t *ict, login_event_ctx_t *ctx); 94a6d42e7dSPeter Dunlap 95a6d42e7dSPeter Dunlap static void 96a6d42e7dSPeter Dunlap login_sm_done(iscsit_conn_t *ict, login_event_ctx_t *ctx); 97a6d42e7dSPeter Dunlap 98a6d42e7dSPeter Dunlap static void 99a6d42e7dSPeter Dunlap login_sm_error(iscsit_conn_t *ict, login_event_ctx_t *ctx); 100a6d42e7dSPeter Dunlap 101a6d42e7dSPeter Dunlap static void 102a6d42e7dSPeter Dunlap login_sm_new_state(iscsit_conn_t *ict, login_event_ctx_t *ctx, 103a6d42e7dSPeter Dunlap iscsit_login_state_t new_state); 104a6d42e7dSPeter Dunlap 105a6d42e7dSPeter Dunlap static void 106a6d42e7dSPeter Dunlap login_sm_send_ack(iscsit_conn_t *ict, idm_pdu_t *pdu); 107a6d42e7dSPeter Dunlap 108a6d42e7dSPeter Dunlap static idm_status_t 109a6d42e7dSPeter Dunlap login_sm_validate_ack(iscsit_conn_t *ict, idm_pdu_t *pdu); 110a6d42e7dSPeter Dunlap 111a6d42e7dSPeter Dunlap static boolean_t 1124142b486SJames Moore login_sm_is_last_response(idm_pdu_t *pdu); 113a6d42e7dSPeter Dunlap 114a6d42e7dSPeter Dunlap static void 115a6d42e7dSPeter Dunlap login_sm_handle_initial_login(iscsit_conn_t *ict, idm_pdu_t *pdu); 116a6d42e7dSPeter Dunlap 117a6d42e7dSPeter Dunlap static void 1184142b486SJames Moore login_sm_send_next_response(iscsit_conn_t *ict, idm_pdu_t *pdu); 119a6d42e7dSPeter Dunlap 120a6d42e7dSPeter Dunlap static void 121a6d42e7dSPeter Dunlap login_sm_process_request(iscsit_conn_t *ict); 122a6d42e7dSPeter Dunlap 123a6d42e7dSPeter Dunlap static idm_status_t 124a6d42e7dSPeter Dunlap login_sm_req_pdu_check(iscsit_conn_t *ict, idm_pdu_t *pdu); 125a6d42e7dSPeter Dunlap 126a6d42e7dSPeter Dunlap static idm_status_t 127a6d42e7dSPeter Dunlap login_sm_process_nvlist(iscsit_conn_t *ict); 128a6d42e7dSPeter Dunlap 129a6d42e7dSPeter Dunlap static idm_status_t 130a6d42e7dSPeter Dunlap login_sm_check_security(iscsit_conn_t *ict); 131a6d42e7dSPeter Dunlap 1324142b486SJames Moore static idm_pdu_t * 133a6d42e7dSPeter Dunlap login_sm_build_login_response(iscsit_conn_t *ict); 134a6d42e7dSPeter Dunlap 135a6d42e7dSPeter Dunlap static void 136a6d42e7dSPeter Dunlap login_sm_ffp_actions(iscsit_conn_t *ict); 137a6d42e7dSPeter Dunlap 138a6d42e7dSPeter Dunlap static idm_status_t 139a6d42e7dSPeter Dunlap login_sm_validate_initial_parameters(iscsit_conn_t *ict); 140a6d42e7dSPeter Dunlap 141a6d42e7dSPeter Dunlap static idm_status_t 142a6d42e7dSPeter Dunlap login_sm_session_bind(iscsit_conn_t *ict); 143a6d42e7dSPeter Dunlap 144a6d42e7dSPeter Dunlap static idm_status_t 145a6d42e7dSPeter Dunlap login_sm_set_auth(iscsit_conn_t *ict); 146a6d42e7dSPeter Dunlap 147a6d42e7dSPeter Dunlap static idm_status_t 148a6d42e7dSPeter Dunlap login_sm_session_register(iscsit_conn_t *ict); 149a6d42e7dSPeter Dunlap 150a6d42e7dSPeter Dunlap static kv_status_t 151a6d42e7dSPeter Dunlap iscsit_handle_key(iscsit_conn_t *ict, nvpair_t *nvp, char *nvp_name); 152a6d42e7dSPeter Dunlap 153a6d42e7dSPeter Dunlap static kv_status_t 154a6d42e7dSPeter Dunlap iscsit_handle_common_key(iscsit_conn_t *ict, nvpair_t *nvp, 155a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx); 156a6d42e7dSPeter Dunlap 157a6d42e7dSPeter Dunlap static kv_status_t 158a6d42e7dSPeter Dunlap iscsit_handle_security_key(iscsit_conn_t *ict, nvpair_t *nvp, 159a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx); 160a6d42e7dSPeter Dunlap 161a6d42e7dSPeter Dunlap static kv_status_t 162a6d42e7dSPeter Dunlap iscsit_reply_security_key(iscsit_conn_t *ict); 163a6d42e7dSPeter Dunlap 164a6d42e7dSPeter Dunlap static kv_status_t 165a6d42e7dSPeter Dunlap iscsit_handle_operational_key(iscsit_conn_t *ict, nvpair_t *nvp, 166a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx); 167a6d42e7dSPeter Dunlap 168a6d42e7dSPeter Dunlap static kv_status_t 169a6d42e7dSPeter Dunlap iscsit_reply_numerical(iscsit_conn_t *ict, 170a6d42e7dSPeter Dunlap const char *nvp_name, const uint64_t value); 171a6d42e7dSPeter Dunlap 172a6d42e7dSPeter Dunlap static kv_status_t 173a6d42e7dSPeter Dunlap iscsit_reply_string(iscsit_conn_t *ict, 174a6d42e7dSPeter Dunlap const char *nvp_name, const char *text); 175a6d42e7dSPeter Dunlap 176a6d42e7dSPeter Dunlap static kv_status_t 177a6d42e7dSPeter Dunlap iscsit_handle_digest(iscsit_conn_t *ict, nvpair_t *choices, 178a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx); 179a6d42e7dSPeter Dunlap 180a6d42e7dSPeter Dunlap static kv_status_t 181a6d42e7dSPeter Dunlap iscsit_handle_boolean(iscsit_conn_t *ict, nvpair_t *nvp, boolean_t value, 182a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx, boolean_t iscsit_value); 183a6d42e7dSPeter Dunlap 184a6d42e7dSPeter Dunlap static kv_status_t 185a6d42e7dSPeter Dunlap iscsit_handle_numerical(iscsit_conn_t *ict, nvpair_t *nvp, uint64_t value, 186a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx, 187a6d42e7dSPeter Dunlap uint64_t iscsi_min_value, uint64_t iscsi_max_value, 188a6d42e7dSPeter Dunlap uint64_t iscsit_max_value); 189a6d42e7dSPeter Dunlap 190a6d42e7dSPeter Dunlap static void 191a6d42e7dSPeter Dunlap iscsit_process_negotiated_values(iscsit_conn_t *ict); 192a6d42e7dSPeter Dunlap 193a6d42e7dSPeter Dunlap static void 194a6d42e7dSPeter Dunlap login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status); 195a6d42e7dSPeter Dunlap 19656261083SCharles Ting static idm_status_t 19756261083SCharles Ting iscsit_add_declarative_keys(iscsit_conn_t *ict); 19856261083SCharles Ting 1991ef61828SYuri Pankov static char * 2001ef61828SYuri Pankov iscsit_fold_name(char *name, size_t *buflen); 2011ef61828SYuri Pankov 20256261083SCharles Ting uint64_t max_dataseglen_target = ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH; 20356261083SCharles Ting 2043fc1e17eSPriya Krishnan /* 2053fc1e17eSPriya Krishnan * global mutex defined in iscsit.c to enforce 2063fc1e17eSPriya Krishnan * login_sm_session_bind as a critical section 2073fc1e17eSPriya Krishnan */ 2083fc1e17eSPriya Krishnan extern kmutex_t login_sm_session_mutex; 2093fc1e17eSPriya Krishnan 210a6d42e7dSPeter Dunlap idm_status_t 211a6d42e7dSPeter Dunlap iscsit_login_sm_init(iscsit_conn_t *ict) 212a6d42e7dSPeter Dunlap { 213a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 214a6d42e7dSPeter Dunlap 215a6d42e7dSPeter Dunlap bzero(lsm, sizeof (iscsit_conn_login_t)); 216a6d42e7dSPeter Dunlap 217a6d42e7dSPeter Dunlap (void) nvlist_alloc(&lsm->icl_negotiated_values, NV_UNIQUE_NAME, 218a6d42e7dSPeter Dunlap KM_SLEEP); 219a6d42e7dSPeter Dunlap 220a6d42e7dSPeter Dunlap /* 221a6d42e7dSPeter Dunlap * Hold connection until the login state machine completes 222a6d42e7dSPeter Dunlap */ 223a6d42e7dSPeter Dunlap iscsit_conn_hold(ict); 224a6d42e7dSPeter Dunlap 225a6d42e7dSPeter Dunlap /* 226a6d42e7dSPeter Dunlap * Pre-allocating a login response PDU means we will always be 227a6d42e7dSPeter Dunlap * able to respond to a login request -- even if we can't allocate 228a6d42e7dSPeter Dunlap * a data buffer to hold the text responses we can at least send 229a6d42e7dSPeter Dunlap * a login failure. 230a6d42e7dSPeter Dunlap */ 231a6d42e7dSPeter Dunlap lsm->icl_login_resp_tmpl = kmem_zalloc(sizeof (iscsi_login_rsp_hdr_t), 232a6d42e7dSPeter Dunlap KM_SLEEP); 233a6d42e7dSPeter Dunlap 234a6d42e7dSPeter Dunlap idm_sm_audit_init(&lsm->icl_state_audit); 235a6d42e7dSPeter Dunlap mutex_init(&lsm->icl_mutex, NULL, MUTEX_DEFAULT, NULL); 236a6d42e7dSPeter Dunlap list_create(&lsm->icl_login_events, sizeof (login_event_ctx_t), 237a6d42e7dSPeter Dunlap offsetof(login_event_ctx_t, le_ctx_node)); 238a6d42e7dSPeter Dunlap list_create(&lsm->icl_pdu_list, sizeof (idm_pdu_t), 239a6d42e7dSPeter Dunlap offsetof(idm_pdu_t, isp_client_lnd)); 240a6d42e7dSPeter Dunlap 241a6d42e7dSPeter Dunlap lsm->icl_login_state = ILS_LOGIN_INIT; 242a6d42e7dSPeter Dunlap lsm->icl_login_last_state = ILS_LOGIN_INIT; 243a6d42e7dSPeter Dunlap 244a6d42e7dSPeter Dunlap /* 245a6d42e7dSPeter Dunlap * Initialize operational parameters to default values. Anything 246a6d42e7dSPeter Dunlap * we don't specifically negotiate stays at the default. 247a6d42e7dSPeter Dunlap */ 248a6d42e7dSPeter Dunlap ict->ict_op.op_discovery_session = B_FALSE; 249a6d42e7dSPeter Dunlap ict->ict_op.op_initial_r2t = ISCSI_DEFAULT_INITIALR2T; 250a6d42e7dSPeter Dunlap ict->ict_op.op_immed_data = ISCSI_DEFAULT_IMMEDIATE_DATA; 251a6d42e7dSPeter Dunlap ict->ict_op.op_data_pdu_in_order = ISCSI_DEFAULT_DATA_PDU_IN_ORDER; 252a6d42e7dSPeter Dunlap ict->ict_op.op_data_sequence_in_order = 253a6d42e7dSPeter Dunlap ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER; 254a6d42e7dSPeter Dunlap ict->ict_op.op_max_connections = ISCSI_DEFAULT_MAX_CONNECTIONS; 255a6d42e7dSPeter Dunlap ict->ict_op.op_max_recv_data_segment_length = 256a6d42e7dSPeter Dunlap ISCSI_DEFAULT_MAX_RECV_SEG_LEN; 257a6d42e7dSPeter Dunlap ict->ict_op.op_max_burst_length = ISCSI_DEFAULT_MAX_BURST_LENGTH; 258a6d42e7dSPeter Dunlap ict->ict_op.op_first_burst_length = ISCSI_DEFAULT_FIRST_BURST_LENGTH; 259a6d42e7dSPeter Dunlap ict->ict_op.op_default_time_2_wait = ISCSI_DEFAULT_TIME_TO_WAIT; 260a6d42e7dSPeter Dunlap ict->ict_op.op_default_time_2_retain = ISCSI_DEFAULT_TIME_TO_RETAIN; 261a6d42e7dSPeter Dunlap ict->ict_op.op_max_outstanding_r2t = ISCSI_DEFAULT_MAX_OUT_R2T; 262a6d42e7dSPeter Dunlap ict->ict_op.op_error_recovery_level = 263a6d42e7dSPeter Dunlap ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL; 264a6d42e7dSPeter Dunlap 265a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 266a6d42e7dSPeter Dunlap } 267a6d42e7dSPeter Dunlap 268a6d42e7dSPeter Dunlap static void 269a6d42e7dSPeter Dunlap login_resp_complete_cb(idm_pdu_t *pdu, idm_status_t status) 270a6d42e7dSPeter Dunlap { 271a6d42e7dSPeter Dunlap iscsit_conn_t *ict = pdu->isp_private; 272a6d42e7dSPeter Dunlap 273a6d42e7dSPeter Dunlap /* 2744142b486SJames Moore * Check that this is a login pdu 275a6d42e7dSPeter Dunlap */ 276a6d42e7dSPeter Dunlap ASSERT((pdu->isp_flags & IDM_PDU_LOGIN_TX) != 0); 2774142b486SJames Moore idm_pdu_free(pdu); 278a6d42e7dSPeter Dunlap 279a6d42e7dSPeter Dunlap if ((status != IDM_STATUS_SUCCESS) || 280a6d42e7dSPeter Dunlap (ict->ict_login_sm.icl_login_resp_err_class != 0)) { 2814142b486SJames Moore /* 2824142b486SJames Moore * Transport or login error occurred. 2834142b486SJames Moore */ 284a6d42e7dSPeter Dunlap iscsit_login_sm_event(ict, ILE_LOGIN_ERROR, NULL); 285a6d42e7dSPeter Dunlap } 2864142b486SJames Moore iscsit_conn_rele(ict); 287a6d42e7dSPeter Dunlap } 288a6d42e7dSPeter Dunlap 289a6d42e7dSPeter Dunlap void 290a6d42e7dSPeter Dunlap iscsit_login_sm_fini(iscsit_conn_t *ict) 291a6d42e7dSPeter Dunlap { 292a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 293a6d42e7dSPeter Dunlap 294a6d42e7dSPeter Dunlap mutex_enter(&lsm->icl_mutex); 295a6d42e7dSPeter Dunlap list_destroy(&lsm->icl_pdu_list); 296a6d42e7dSPeter Dunlap list_destroy(&lsm->icl_login_events); 297a6d42e7dSPeter Dunlap 298a6d42e7dSPeter Dunlap kmem_free(lsm->icl_login_resp_tmpl, sizeof (iscsi_login_rsp_hdr_t)); 299a6d42e7dSPeter Dunlap 300a6d42e7dSPeter Dunlap /* clean up the login response idm text buffer */ 301a6d42e7dSPeter Dunlap if (lsm->icl_login_resp_itb != NULL) { 302a6d42e7dSPeter Dunlap idm_itextbuf_free(lsm->icl_login_resp_itb); 303a6d42e7dSPeter Dunlap lsm->icl_login_resp_itb = NULL; 304a6d42e7dSPeter Dunlap } 305a6d42e7dSPeter Dunlap 306a6d42e7dSPeter Dunlap nvlist_free(lsm->icl_negotiated_values); 3074142b486SJames Moore mutex_destroy(&lsm->icl_mutex); 308a6d42e7dSPeter Dunlap } 309a6d42e7dSPeter Dunlap 310a6d42e7dSPeter Dunlap void 311a6d42e7dSPeter Dunlap iscsit_login_sm_event(iscsit_conn_t *ict, iscsit_login_event_t event, 312a6d42e7dSPeter Dunlap idm_pdu_t *pdu) 313a6d42e7dSPeter Dunlap { 314a6d42e7dSPeter Dunlap /* 315a6d42e7dSPeter Dunlap * This is a bit ugly but if we're already in ILS_LOGIN_ERROR 316a6d42e7dSPeter Dunlap * or ILS_LOGIN_DONE then just drop any additional events. They 317a6d42e7dSPeter Dunlap * won't change the state and it's possible we've already called 318a6d42e7dSPeter Dunlap * iscsit_login_sm_fini in which case the mutex is destroyed. 319a6d42e7dSPeter Dunlap */ 320a6d42e7dSPeter Dunlap if ((ict->ict_login_sm.icl_login_state == ILS_LOGIN_ERROR) || 321a6d42e7dSPeter Dunlap (ict->ict_login_sm.icl_login_state == ILS_LOGIN_DONE)) 322a6d42e7dSPeter Dunlap return; 323a6d42e7dSPeter Dunlap 324a6d42e7dSPeter Dunlap mutex_enter(&ict->ict_login_sm.icl_mutex); 325a6d42e7dSPeter Dunlap iscsit_login_sm_event_locked(ict, event, pdu); 326a6d42e7dSPeter Dunlap mutex_exit(&ict->ict_login_sm.icl_mutex); 327a6d42e7dSPeter Dunlap } 328a6d42e7dSPeter Dunlap void 329a6d42e7dSPeter Dunlap iscsit_login_sm_event_locked(iscsit_conn_t *ict, iscsit_login_event_t event, 330a6d42e7dSPeter Dunlap idm_pdu_t *pdu) 331a6d42e7dSPeter Dunlap { 332a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 333a6d42e7dSPeter Dunlap login_event_ctx_t *ctx; 334a6d42e7dSPeter Dunlap 3354142b486SJames Moore ASSERT(mutex_owned(&lsm->icl_mutex)); 336a6d42e7dSPeter Dunlap ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP); 337a6d42e7dSPeter Dunlap 338a6d42e7dSPeter Dunlap ctx->le_ctx_event = event; 339a6d42e7dSPeter Dunlap ctx->le_pdu = pdu; 340a6d42e7dSPeter Dunlap 341a6d42e7dSPeter Dunlap list_insert_tail(&lsm->icl_login_events, ctx); 342a6d42e7dSPeter Dunlap 343a6d42e7dSPeter Dunlap /* 344a6d42e7dSPeter Dunlap * Use the icl_busy flag to keep the state machine single threaded. 345a6d42e7dSPeter Dunlap * This also serves as recursion avoidance since this flag will 346a6d42e7dSPeter Dunlap * always be set if we call login_sm_event from within the 347a6d42e7dSPeter Dunlap * state machine code. 348a6d42e7dSPeter Dunlap */ 349a6d42e7dSPeter Dunlap if (!lsm->icl_busy) { 350a6d42e7dSPeter Dunlap lsm->icl_busy = B_TRUE; 351a6d42e7dSPeter Dunlap while (!list_is_empty(&lsm->icl_login_events)) { 352a6d42e7dSPeter Dunlap ctx = list_head(&lsm->icl_login_events); 353a6d42e7dSPeter Dunlap list_remove(&lsm->icl_login_events, ctx); 354a6d42e7dSPeter Dunlap idm_sm_audit_event(&lsm->icl_state_audit, 355a6d42e7dSPeter Dunlap SAS_ISCSIT_LOGIN, (int)lsm->icl_login_state, 356a6d42e7dSPeter Dunlap (int)ctx->le_ctx_event, (uintptr_t)pdu); 357a6d42e7dSPeter Dunlap 35830e7468fSPeter Dunlap /* 35930e7468fSPeter Dunlap * If the lsm is in a terminal state, just drain 36030e7468fSPeter Dunlap * any remaining events. 36130e7468fSPeter Dunlap */ 36230e7468fSPeter Dunlap if ((lsm->icl_login_state == ILS_LOGIN_ERROR) || 36330e7468fSPeter Dunlap (lsm->icl_login_state == ILS_LOGIN_DONE)) { 36430e7468fSPeter Dunlap kmem_free(ctx, sizeof (*ctx)); 36530e7468fSPeter Dunlap continue; 36630e7468fSPeter Dunlap } 367a6d42e7dSPeter Dunlap mutex_exit(&lsm->icl_mutex); 368a6d42e7dSPeter Dunlap login_sm_event_dispatch(lsm, ict, ctx); 369a6d42e7dSPeter Dunlap mutex_enter(&lsm->icl_mutex); 370a6d42e7dSPeter Dunlap } 371a6d42e7dSPeter Dunlap lsm->icl_busy = B_FALSE; 372a6d42e7dSPeter Dunlap 373a6d42e7dSPeter Dunlap /* 374a6d42e7dSPeter Dunlap * When the state machine reaches ILS_LOGIN_DONE or 375a6d42e7dSPeter Dunlap * ILS_LOGIN_ERROR state the login process has completed 376a6d42e7dSPeter Dunlap * and it's time to cleanup. The state machine code will 377a6d42e7dSPeter Dunlap * mark itself "complete" when this happens. 378a6d42e7dSPeter Dunlap * 379a6d42e7dSPeter Dunlap * To protect against spurious events (which shouldn't 380a6d42e7dSPeter Dunlap * happen) set icl_busy again. 381a6d42e7dSPeter Dunlap */ 382a6d42e7dSPeter Dunlap if (lsm->icl_login_complete) { 383a6d42e7dSPeter Dunlap lsm->icl_busy = B_TRUE; 384a6d42e7dSPeter Dunlap if (taskq_dispatch(iscsit_global.global_dispatch_taskq, 385*fc8ae2ecSToomas Soome login_sm_complete, ict, DDI_SLEEP) == 386*fc8ae2ecSToomas Soome TASKQID_INVALID) { 387a6d42e7dSPeter Dunlap cmn_err(CE_WARN, "iscsit_login_sm_event_locked:" 388a6d42e7dSPeter Dunlap " Failed to dispatch task"); 389a6d42e7dSPeter Dunlap } 390a6d42e7dSPeter Dunlap } 391a6d42e7dSPeter Dunlap } 392a6d42e7dSPeter Dunlap } 393a6d42e7dSPeter Dunlap 394a6d42e7dSPeter Dunlap static void 395a6d42e7dSPeter Dunlap login_sm_complete(void *ict_void) 396a6d42e7dSPeter Dunlap { 397a6d42e7dSPeter Dunlap iscsit_conn_t *ict = ict_void; 398a6d42e7dSPeter Dunlap 399a6d42e7dSPeter Dunlap /* 4004142b486SJames Moore * State machine has run to completion, resources 4014142b486SJames Moore * will be cleaned up when connection is destroyed. 402a6d42e7dSPeter Dunlap */ 4034142b486SJames Moore iscsit_conn_rele(ict); 404a6d42e7dSPeter Dunlap } 405a6d42e7dSPeter Dunlap 406a6d42e7dSPeter Dunlap static void 407a6d42e7dSPeter Dunlap login_sm_event_dispatch(iscsit_conn_login_t *lsm, iscsit_conn_t *ict, 408a6d42e7dSPeter Dunlap login_event_ctx_t *ctx) 409a6d42e7dSPeter Dunlap { 410a6d42e7dSPeter Dunlap idm_pdu_t *pdu = ctx->le_pdu; /* Only valid for some events */ 411a6d42e7dSPeter Dunlap 412a6d42e7dSPeter Dunlap DTRACE_PROBE2(login__event, iscsit_conn_t *, ict, 413a6d42e7dSPeter Dunlap login_event_ctx_t *, ctx); 414a6d42e7dSPeter Dunlap 415a6d42e7dSPeter Dunlap IDM_SM_LOG(CE_NOTE, "login_sm_event_dispatch: ict %p event %s(%d)", 416a6d42e7dSPeter Dunlap (void *)ict, 417a6d42e7dSPeter Dunlap iscsit_ile_name[ctx->le_ctx_event], ctx->le_ctx_event); 418a6d42e7dSPeter Dunlap 419a6d42e7dSPeter Dunlap /* State independent actions */ 420a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 421a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 422a6d42e7dSPeter Dunlap /* Perform basic sanity checks on the header */ 423a6d42e7dSPeter Dunlap if (login_sm_req_pdu_check(ict, pdu) != IDM_STATUS_SUCCESS) { 4244142b486SJames Moore idm_pdu_t *rpdu; 4254142b486SJames Moore 426a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 427a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_INVALID_REQUEST); 428a6d42e7dSPeter Dunlap /* 429a6d42e7dSPeter Dunlap * If we haven't processed any PDU's yet then use 430a6d42e7dSPeter Dunlap * this one as a template for the response 431a6d42e7dSPeter Dunlap */ 432a6d42e7dSPeter Dunlap if (ict->ict_login_sm.icl_login_resp_tmpl->opcode == 0) 433a6d42e7dSPeter Dunlap login_sm_handle_initial_login(ict, pdu); 4344142b486SJames Moore rpdu = login_sm_build_login_response(ict); 4354142b486SJames Moore login_sm_send_next_response(ict, rpdu); 436a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 43730e7468fSPeter Dunlap kmem_free(ctx, sizeof (*ctx)); 438a6d42e7dSPeter Dunlap return; 439a6d42e7dSPeter Dunlap } 440a6d42e7dSPeter Dunlap break; 441a6d42e7dSPeter Dunlap default: 442a6d42e7dSPeter Dunlap break; 443a6d42e7dSPeter Dunlap } 444a6d42e7dSPeter Dunlap 445a6d42e7dSPeter Dunlap /* State dependent actions */ 446a6d42e7dSPeter Dunlap switch (lsm->icl_login_state) { 447a6d42e7dSPeter Dunlap case ILS_LOGIN_INIT: 448a6d42e7dSPeter Dunlap login_sm_init(ict, ctx); 449a6d42e7dSPeter Dunlap break; 450a6d42e7dSPeter Dunlap case ILS_LOGIN_WAITING: 451a6d42e7dSPeter Dunlap login_sm_waiting(ict, ctx); 452a6d42e7dSPeter Dunlap break; 453a6d42e7dSPeter Dunlap case ILS_LOGIN_PROCESSING: 454a6d42e7dSPeter Dunlap login_sm_processing(ict, ctx); 455a6d42e7dSPeter Dunlap break; 456a6d42e7dSPeter Dunlap case ILS_LOGIN_RESPONDING: 457a6d42e7dSPeter Dunlap login_sm_responding(ict, ctx); 458a6d42e7dSPeter Dunlap break; 459a6d42e7dSPeter Dunlap case ILS_LOGIN_RESPONDED: 460a6d42e7dSPeter Dunlap login_sm_responded(ict, ctx); 461a6d42e7dSPeter Dunlap break; 462a6d42e7dSPeter Dunlap case ILS_LOGIN_FFP: 463a6d42e7dSPeter Dunlap login_sm_ffp(ict, ctx); 464a6d42e7dSPeter Dunlap break; 465a6d42e7dSPeter Dunlap case ILS_LOGIN_DONE: 466a6d42e7dSPeter Dunlap login_sm_done(ict, ctx); 467a6d42e7dSPeter Dunlap break; 468a6d42e7dSPeter Dunlap case ILS_LOGIN_ERROR: 469a6d42e7dSPeter Dunlap login_sm_error(ict, ctx); 470a6d42e7dSPeter Dunlap break; 471a6d42e7dSPeter Dunlap } 472a6d42e7dSPeter Dunlap 473a6d42e7dSPeter Dunlap kmem_free(ctx, sizeof (*ctx)); 474a6d42e7dSPeter Dunlap } 475a6d42e7dSPeter Dunlap 476a6d42e7dSPeter Dunlap static void 477a6d42e7dSPeter Dunlap login_sm_init(iscsit_conn_t *ict, login_event_ctx_t *ctx) 478a6d42e7dSPeter Dunlap { 479a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 480a6d42e7dSPeter Dunlap 481a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 482a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 483a6d42e7dSPeter Dunlap pdu = ctx->le_pdu; 484a6d42e7dSPeter Dunlap 485a6d42e7dSPeter Dunlap /* 486a6d42e7dSPeter Dunlap * This is the first login PDU we've received so use 487a6d42e7dSPeter Dunlap * it to build the login response template and set our CSG. 488a6d42e7dSPeter Dunlap */ 489a6d42e7dSPeter Dunlap login_sm_handle_initial_login(ict, pdu); 490a6d42e7dSPeter Dunlap 491a6d42e7dSPeter Dunlap /* 492a6d42e7dSPeter Dunlap * Accumulate all the login PDU's that make up this 493a6d42e7dSPeter Dunlap * request on a queue. 494a6d42e7dSPeter Dunlap */ 495a6d42e7dSPeter Dunlap mutex_enter(&ict->ict_login_sm.icl_mutex); 496a6d42e7dSPeter Dunlap list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu); 497a6d42e7dSPeter Dunlap mutex_exit(&ict->ict_login_sm.icl_mutex); 498a6d42e7dSPeter Dunlap 499a6d42e7dSPeter Dunlap if (pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE) { 500a6d42e7dSPeter Dunlap login_sm_send_ack(ict, pdu); 501a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_WAITING); 502a6d42e7dSPeter Dunlap } else { 503a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING); 504a6d42e7dSPeter Dunlap } 505a6d42e7dSPeter Dunlap break; 506a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 507a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 508a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 509a6d42e7dSPeter Dunlap break; 510a6d42e7dSPeter Dunlap default: 511a6d42e7dSPeter Dunlap ASSERT(0); 512a6d42e7dSPeter Dunlap } 513a6d42e7dSPeter Dunlap } 514a6d42e7dSPeter Dunlap 515a6d42e7dSPeter Dunlap static void 516a6d42e7dSPeter Dunlap login_sm_waiting(iscsit_conn_t *ict, login_event_ctx_t *ctx) 517a6d42e7dSPeter Dunlap { 518a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 519a6d42e7dSPeter Dunlap 520a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 521a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 522a6d42e7dSPeter Dunlap pdu = ctx->le_pdu; 523a6d42e7dSPeter Dunlap mutex_enter(&ict->ict_login_sm.icl_mutex); 524a6d42e7dSPeter Dunlap list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu); 525a6d42e7dSPeter Dunlap mutex_exit(&ict->ict_login_sm.icl_mutex); 526a6d42e7dSPeter Dunlap if (!(pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE)) { 527a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING); 528a6d42e7dSPeter Dunlap } else { 529a6d42e7dSPeter Dunlap login_sm_send_ack(ict, pdu); 530a6d42e7dSPeter Dunlap } 531a6d42e7dSPeter Dunlap break; 532a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 533a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 534a6d42e7dSPeter Dunlap break; 535a6d42e7dSPeter Dunlap case ILE_LOGIN_RESP_COMPLETE: 536a6d42e7dSPeter Dunlap break; 537a6d42e7dSPeter Dunlap default: 538a6d42e7dSPeter Dunlap ASSERT(0); 539a6d42e7dSPeter Dunlap } 540a6d42e7dSPeter Dunlap } 541a6d42e7dSPeter Dunlap 542a6d42e7dSPeter Dunlap static void 543a6d42e7dSPeter Dunlap login_sm_processing(iscsit_conn_t *ict, login_event_ctx_t *ctx) 544a6d42e7dSPeter Dunlap { 545a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 546a6d42e7dSPeter Dunlap case ILE_LOGIN_RESP_READY: 547a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_RESPONDING); 548a6d42e7dSPeter Dunlap break; 549a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 550a6d42e7dSPeter Dunlap idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS); 551a6d42e7dSPeter Dunlap /*FALLTHROUGH*/ 552a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 553a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 554a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 555a6d42e7dSPeter Dunlap break; 556a6d42e7dSPeter Dunlap default: 557a6d42e7dSPeter Dunlap ASSERT(0); 558a6d42e7dSPeter Dunlap } 559a6d42e7dSPeter Dunlap } 560a6d42e7dSPeter Dunlap 561a6d42e7dSPeter Dunlap static void 562a6d42e7dSPeter Dunlap login_sm_responding(iscsit_conn_t *ict, login_event_ctx_t *ctx) 563a6d42e7dSPeter Dunlap { 5644142b486SJames Moore idm_pdu_t *pdu, *rpdu; 565a6d42e7dSPeter Dunlap 566a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 567a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 568a6d42e7dSPeter Dunlap pdu = ctx->le_pdu; 569a6d42e7dSPeter Dunlap /* 570a6d42e7dSPeter Dunlap * We should only be in "responding" state if we have not 571a6d42e7dSPeter Dunlap * sent the last PDU of a multi-PDU login response sequence. 572a6d42e7dSPeter Dunlap * In that case we expect this received PDU to be an 573a6d42e7dSPeter Dunlap * acknowledgement from the initiator (login PDU with C 574a6d42e7dSPeter Dunlap * bit cleared and no data). If it's the acknowledgement 575a6d42e7dSPeter Dunlap * we are expecting then we send the next PDU in the login 576a6d42e7dSPeter Dunlap * response sequence. Otherwise it's a protocol error and 577a6d42e7dSPeter Dunlap * the login fails. 578a6d42e7dSPeter Dunlap */ 579a6d42e7dSPeter Dunlap if (login_sm_validate_ack(ict, pdu) == IDM_STATUS_SUCCESS) { 5804142b486SJames Moore rpdu = login_sm_build_login_response(ict); 5814142b486SJames Moore login_sm_send_next_response(ict, rpdu); 582a6d42e7dSPeter Dunlap } else { 583a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 584a6d42e7dSPeter Dunlap } 585a6d42e7dSPeter Dunlap idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 586a6d42e7dSPeter Dunlap break; 587a6d42e7dSPeter Dunlap case ILE_LOGIN_FFP: 588a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_FFP); 589a6d42e7dSPeter Dunlap break; 590a6d42e7dSPeter Dunlap case ILE_LOGIN_RESP_COMPLETE: 591a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_RESPONDED); 592a6d42e7dSPeter Dunlap break; 593a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 594a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 595a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 596a6d42e7dSPeter Dunlap break; 597a6d42e7dSPeter Dunlap default: 598a6d42e7dSPeter Dunlap ASSERT(0); 599a6d42e7dSPeter Dunlap } 600a6d42e7dSPeter Dunlap } 601a6d42e7dSPeter Dunlap 602a6d42e7dSPeter Dunlap static void 603a6d42e7dSPeter Dunlap login_sm_responded(iscsit_conn_t *ict, login_event_ctx_t *ctx) 604a6d42e7dSPeter Dunlap { 605a6d42e7dSPeter Dunlap idm_pdu_t *pdu; 606a6d42e7dSPeter Dunlap iscsi_login_hdr_t *lh; 607a6d42e7dSPeter Dunlap 608a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 609a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 610a6d42e7dSPeter Dunlap pdu = ctx->le_pdu; 611a6d42e7dSPeter Dunlap lh = (iscsi_login_hdr_t *)pdu->isp_hdr; 612a6d42e7dSPeter Dunlap /* 613a6d42e7dSPeter Dunlap * Set the CSG, NSG and Transit bits based on the this PDU. 614a6d42e7dSPeter Dunlap * The CSG already validated in login_sm_req_pdu_check(). 615a6d42e7dSPeter Dunlap * We'll clear the transit bit if we encounter any login 616a6d42e7dSPeter Dunlap * parameters in the request that required an additional 617a6d42e7dSPeter Dunlap * login transfer (i.e. no acceptable 618a6d42e7dSPeter Dunlap * choices in range or we needed to change a boolean 619a6d42e7dSPeter Dunlap * value from "Yes" to "No"). 620a6d42e7dSPeter Dunlap */ 621a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_csg = 622a6d42e7dSPeter Dunlap ISCSI_LOGIN_CURRENT_STAGE(lh->flags); 623a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_nsg = 624a6d42e7dSPeter Dunlap ISCSI_LOGIN_NEXT_STAGE(lh->flags); 625a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_transit = 626a6d42e7dSPeter Dunlap lh->flags & ISCSI_FLAG_LOGIN_TRANSIT; 627a6d42e7dSPeter Dunlap mutex_enter(&ict->ict_login_sm.icl_mutex); 628a6d42e7dSPeter Dunlap list_insert_tail(&ict->ict_login_sm.icl_pdu_list, pdu); 629a6d42e7dSPeter Dunlap mutex_exit(&ict->ict_login_sm.icl_mutex); 630a6d42e7dSPeter Dunlap if (pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE) { 631a6d42e7dSPeter Dunlap login_sm_send_ack(ict, pdu); 632a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_WAITING); 633a6d42e7dSPeter Dunlap } else { 634a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_PROCESSING); 635a6d42e7dSPeter Dunlap } 636a6d42e7dSPeter Dunlap break; 637a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 638a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 639a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 640a6d42e7dSPeter Dunlap break; 641a6d42e7dSPeter Dunlap default: 642a6d42e7dSPeter Dunlap ASSERT(0); 643a6d42e7dSPeter Dunlap } 644a6d42e7dSPeter Dunlap } 645a6d42e7dSPeter Dunlap 646a6d42e7dSPeter Dunlap static void 647a6d42e7dSPeter Dunlap login_sm_ffp(iscsit_conn_t *ict, login_event_ctx_t *ctx) 648a6d42e7dSPeter Dunlap { 649a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 650a6d42e7dSPeter Dunlap case ILE_LOGIN_RESP_COMPLETE: 651a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_DONE); 652a6d42e7dSPeter Dunlap break; 653a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 654a6d42e7dSPeter Dunlap case ILE_LOGIN_ERROR: 655a6d42e7dSPeter Dunlap login_sm_new_state(ict, ctx, ILS_LOGIN_ERROR); 656a6d42e7dSPeter Dunlap break; 657a6d42e7dSPeter Dunlap default: 658a6d42e7dSPeter Dunlap ASSERT(0); 659a6d42e7dSPeter Dunlap } 660a6d42e7dSPeter Dunlap 661a6d42e7dSPeter Dunlap } 662a6d42e7dSPeter Dunlap 663a6d42e7dSPeter Dunlap /*ARGSUSED*/ 664a6d42e7dSPeter Dunlap static void 665a6d42e7dSPeter Dunlap login_sm_done(iscsit_conn_t *ict, login_event_ctx_t *ctx) 666a6d42e7dSPeter Dunlap { 667a6d42e7dSPeter Dunlap /* Terminal state, we should get no events */ 668a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 669a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 670a6d42e7dSPeter Dunlap /* 671a6d42e7dSPeter Dunlap * We've already processed everything we're going to 672a6d42e7dSPeter Dunlap * process. Drop any additional login PDU's. 673a6d42e7dSPeter Dunlap */ 674a6d42e7dSPeter Dunlap idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS); 675a6d42e7dSPeter Dunlap break; 676a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 677a6d42e7dSPeter Dunlap /* Don't care */ 678a6d42e7dSPeter Dunlap break; 679a6d42e7dSPeter Dunlap default: 680a6d42e7dSPeter Dunlap ASSERT(0); 681a6d42e7dSPeter Dunlap } 682a6d42e7dSPeter Dunlap } 683a6d42e7dSPeter Dunlap 684a6d42e7dSPeter Dunlap /*ARGSUSED*/ 685a6d42e7dSPeter Dunlap static void 686a6d42e7dSPeter Dunlap login_sm_error(iscsit_conn_t *ict, login_event_ctx_t *ctx) 687a6d42e7dSPeter Dunlap { 688a6d42e7dSPeter Dunlap switch (ctx->le_ctx_event) { 689a6d42e7dSPeter Dunlap case ILE_LOGIN_RCV: 690a6d42e7dSPeter Dunlap /* 691a6d42e7dSPeter Dunlap * We've already processed everything we're going to 692a6d42e7dSPeter Dunlap * process. Drop any additional login PDU's. 693a6d42e7dSPeter Dunlap */ 694a6d42e7dSPeter Dunlap idm_pdu_complete(ctx->le_pdu, IDM_STATUS_SUCCESS); 695a6d42e7dSPeter Dunlap break; 696a6d42e7dSPeter Dunlap case ILE_LOGIN_CONN_ERROR: 697a6d42e7dSPeter Dunlap /* Don't care */ 698a6d42e7dSPeter Dunlap break; 699a6d42e7dSPeter Dunlap default: 700a6d42e7dSPeter Dunlap ASSERT(0); 701a6d42e7dSPeter Dunlap } 702a6d42e7dSPeter Dunlap } 703a6d42e7dSPeter Dunlap 704a6d42e7dSPeter Dunlap static void 705a6d42e7dSPeter Dunlap login_sm_new_state(iscsit_conn_t *ict, login_event_ctx_t *ctx, 706a6d42e7dSPeter Dunlap iscsit_login_state_t new_state) 707a6d42e7dSPeter Dunlap { 708a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 7094142b486SJames Moore idm_pdu_t *rpdu; 710a6d42e7dSPeter Dunlap 711a6d42e7dSPeter Dunlap /* 712a6d42e7dSPeter Dunlap * Validate new state 713a6d42e7dSPeter Dunlap */ 714a6d42e7dSPeter Dunlap ASSERT(new_state != ILS_UNDEFINED); 715a6d42e7dSPeter Dunlap ASSERT3U(new_state, <, ILS_MAX_STATE); 716a6d42e7dSPeter Dunlap 717a6d42e7dSPeter Dunlap new_state = (new_state < ILS_MAX_STATE) ? 718a6d42e7dSPeter Dunlap new_state : ILS_UNDEFINED; 719a6d42e7dSPeter Dunlap 720a6d42e7dSPeter Dunlap IDM_SM_LOG(CE_NOTE, "login_sm_new_state: conn %p " 721a6d42e7dSPeter Dunlap "%s (%d) --> %s (%d)\n", (void *)ict->ict_ic, 722a6d42e7dSPeter Dunlap iscsit_ils_name[lsm->icl_login_state], lsm->icl_login_state, 723a6d42e7dSPeter Dunlap iscsit_ils_name[new_state], new_state); 724a6d42e7dSPeter Dunlap 725a6d42e7dSPeter Dunlap DTRACE_PROBE3(login__state__change, 726a6d42e7dSPeter Dunlap iscsit_conn_t *, ict, login_event_ctx_t *, ctx, 727a6d42e7dSPeter Dunlap iscsit_login_state_t, new_state); 728a6d42e7dSPeter Dunlap 729a6d42e7dSPeter Dunlap mutex_enter(&lsm->icl_mutex); 730a6d42e7dSPeter Dunlap idm_sm_audit_state_change(&lsm->icl_state_audit, SAS_ISCSIT_LOGIN, 731a6d42e7dSPeter Dunlap (int)lsm->icl_login_state, (int)new_state); 732a6d42e7dSPeter Dunlap lsm->icl_login_last_state = lsm->icl_login_state; 733a6d42e7dSPeter Dunlap lsm->icl_login_state = new_state; 734a6d42e7dSPeter Dunlap mutex_exit(&lsm->icl_mutex); 735a6d42e7dSPeter Dunlap 736a6d42e7dSPeter Dunlap switch (lsm->icl_login_state) { 737a6d42e7dSPeter Dunlap case ILS_LOGIN_WAITING: 738a6d42e7dSPeter Dunlap /* Do nothing, waiting for more login PDU's */ 739a6d42e7dSPeter Dunlap break; 740a6d42e7dSPeter Dunlap case ILS_LOGIN_PROCESSING: 741a6d42e7dSPeter Dunlap /* All login PDU's received, process login request */ 742a6d42e7dSPeter Dunlap login_sm_process_request(ict); 743a6d42e7dSPeter Dunlap break; 744a6d42e7dSPeter Dunlap case ILS_LOGIN_RESPONDING: 7454142b486SJames Moore rpdu = login_sm_build_login_response(ict); 7464142b486SJames Moore login_sm_send_next_response(ict, rpdu); 747a6d42e7dSPeter Dunlap break; 748a6d42e7dSPeter Dunlap case ILS_LOGIN_RESPONDED: 749a6d42e7dSPeter Dunlap /* clean up the login response idm text buffer */ 750a6d42e7dSPeter Dunlap if (lsm->icl_login_resp_itb != NULL) { 751a6d42e7dSPeter Dunlap idm_itextbuf_free(lsm->icl_login_resp_itb); 752a6d42e7dSPeter Dunlap lsm->icl_login_resp_itb = NULL; 753a6d42e7dSPeter Dunlap } 754a6d42e7dSPeter Dunlap break; 755a6d42e7dSPeter Dunlap case ILS_LOGIN_FFP: 756a6d42e7dSPeter Dunlap login_sm_ffp_actions(ict); 757a6d42e7dSPeter Dunlap break; 758a6d42e7dSPeter Dunlap case ILS_LOGIN_DONE: 759a6d42e7dSPeter Dunlap case ILS_LOGIN_ERROR: 7604142b486SJames Moore /* 7614142b486SJames Moore * Flag the terminal state for the dispatcher 7624142b486SJames Moore */ 763a6d42e7dSPeter Dunlap lsm->icl_login_complete = B_TRUE; 764a6d42e7dSPeter Dunlap break; 765a6d42e7dSPeter Dunlap case ILS_LOGIN_INIT: /* Initial state, can't return */ 766a6d42e7dSPeter Dunlap default: 767a6d42e7dSPeter Dunlap ASSERT(0); 768a6d42e7dSPeter Dunlap /*NOTREACHED*/ 769a6d42e7dSPeter Dunlap } 770a6d42e7dSPeter Dunlap } 771a6d42e7dSPeter Dunlap 772a6d42e7dSPeter Dunlap /*ARGSUSED*/ 773a6d42e7dSPeter Dunlap static void 774a6d42e7dSPeter Dunlap login_sm_send_ack(iscsit_conn_t *ict, idm_pdu_t *pdu) 775a6d42e7dSPeter Dunlap { 776a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 7774142b486SJames Moore idm_pdu_t *lack; 778a6d42e7dSPeter Dunlap 7794142b486SJames Moore /* 7804142b486SJames Moore * allocate the response pdu 7814142b486SJames Moore */ 7824142b486SJames Moore lack = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0); 7834142b486SJames Moore idm_pdu_init(lack, ict->ict_ic, ict, login_resp_complete_cb); 7844142b486SJames Moore lack->isp_flags |= IDM_PDU_LOGIN_TX; 7854142b486SJames Moore 7864142b486SJames Moore /* 7874142b486SJames Moore * copy the response template into the response pdu 7884142b486SJames Moore */ 7894142b486SJames Moore bcopy(lsm->icl_login_resp_tmpl, lack->isp_hdr, sizeof (iscsi_hdr_t)); 7904142b486SJames Moore 7914142b486SJames Moore iscsit_conn_hold(ict); 7924142b486SJames Moore idm_pdu_tx(lack); 793a6d42e7dSPeter Dunlap } 794a6d42e7dSPeter Dunlap 795a6d42e7dSPeter Dunlap /*ARGSUSED*/ 796a6d42e7dSPeter Dunlap static idm_status_t 797a6d42e7dSPeter Dunlap login_sm_validate_ack(iscsit_conn_t *ict, idm_pdu_t *pdu) 798a6d42e7dSPeter Dunlap { 799a6d42e7dSPeter Dunlap iscsi_hdr_t *ihp = pdu->isp_hdr; 800a6d42e7dSPeter Dunlap if (ihp->flags & ISCSI_FLAG_TEXT_CONTINUE) { 801a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 802a6d42e7dSPeter Dunlap } 803a6d42e7dSPeter Dunlap if (ntoh24(ihp->dlength) != 0) { 804a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 805a6d42e7dSPeter Dunlap } 806a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 807a6d42e7dSPeter Dunlap } 808a6d42e7dSPeter Dunlap 809a6d42e7dSPeter Dunlap static boolean_t 8104142b486SJames Moore login_sm_is_last_response(idm_pdu_t *pdu) 811a6d42e7dSPeter Dunlap { 812a6d42e7dSPeter Dunlap 8134142b486SJames Moore if (pdu->isp_hdr->flags & ISCSI_FLAG_LOGIN_CONTINUE) { 814a6d42e7dSPeter Dunlap return (B_FALSE); 815a6d42e7dSPeter Dunlap } 816a6d42e7dSPeter Dunlap return (B_TRUE); 817a6d42e7dSPeter Dunlap } 818a6d42e7dSPeter Dunlap 819a6d42e7dSPeter Dunlap 820a6d42e7dSPeter Dunlap static void 821a6d42e7dSPeter Dunlap login_sm_handle_initial_login(iscsit_conn_t *ict, idm_pdu_t *pdu) 822a6d42e7dSPeter Dunlap { 823a6d42e7dSPeter Dunlap iscsi_login_hdr_t *lh_req = (iscsi_login_hdr_t *)pdu->isp_hdr; 824a6d42e7dSPeter Dunlap iscsi_login_rsp_hdr_t *lh_resp = 825a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_resp_tmpl; 826a6d42e7dSPeter Dunlap 827a6d42e7dSPeter Dunlap /* 828a6d42e7dSPeter Dunlap * First login PDU, this connection should not have a sesssion 829a6d42e7dSPeter Dunlap * associated. 830a6d42e7dSPeter Dunlap */ 831a6d42e7dSPeter Dunlap ASSERT(ict->ict_sess == NULL); 832a6d42e7dSPeter Dunlap 833a6d42e7dSPeter Dunlap /* 834a6d42e7dSPeter Dunlap * Save off TSIH and ISID for later use in finding a session 835a6d42e7dSPeter Dunlap */ 836a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_cmdsn = ntohl(lh_req->cmdsn); 837a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_tsih = ntohs(lh_req->tsid); 838a6d42e7dSPeter Dunlap bcopy(lh_req->isid, ict->ict_login_sm.icl_isid, ISCSI_ISID_LEN); 839a6d42e7dSPeter Dunlap 840a6d42e7dSPeter Dunlap /* 841a6d42e7dSPeter Dunlap * We'll need the CID as well 842a6d42e7dSPeter Dunlap */ 843a6d42e7dSPeter Dunlap ict->ict_cid = ntohs(lh_req->cid); 844a6d42e7dSPeter Dunlap 845a6d42e7dSPeter Dunlap /* 846a6d42e7dSPeter Dunlap * Set the CSG, NSG and Transit bits based on the first PDU 847a6d42e7dSPeter Dunlap * in the login sequence. The CSG already validated in 848a6d42e7dSPeter Dunlap * login_sm_req_pdu_check(). We'll clear the transit bit if 849a6d42e7dSPeter Dunlap * we encounter any login parameters in the request that 850a6d42e7dSPeter Dunlap * required an additional login transfer (i.e. no acceptable 851a6d42e7dSPeter Dunlap * choices in range or we needed to change a boolean 852a6d42e7dSPeter Dunlap * value from "Yes" to "No"). 853a6d42e7dSPeter Dunlap */ 854a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_csg = 855a6d42e7dSPeter Dunlap ISCSI_LOGIN_CURRENT_STAGE(lh_req->flags); 856a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_nsg = 857a6d42e7dSPeter Dunlap ISCSI_LOGIN_NEXT_STAGE(lh_req->flags); 858a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_login_transit = 859a6d42e7dSPeter Dunlap lh_req->flags & ISCSI_FLAG_LOGIN_TRANSIT; 860a6d42e7dSPeter Dunlap 861a6d42e7dSPeter Dunlap /* 862a6d42e7dSPeter Dunlap * Initialize header for login reject response. This will also 863a6d42e7dSPeter Dunlap * be copied for use as a template for other login responses 864a6d42e7dSPeter Dunlap */ 865a6d42e7dSPeter Dunlap lh_resp->opcode = ISCSI_OP_LOGIN_RSP; 866a6d42e7dSPeter Dunlap lh_resp->max_version = ISCSIT_MAX_VERSION; 867a6d42e7dSPeter Dunlap 868a6d42e7dSPeter Dunlap /* 869a6d42e7dSPeter Dunlap * We already validated that we can support one of the initiator's 870a6d42e7dSPeter Dunlap * versions in login_sm_req_pdu_check(). 871a6d42e7dSPeter Dunlap */ 872a6d42e7dSPeter Dunlap #if (ISCSIT_MAX_VERSION > 0) 873a6d42e7dSPeter Dunlap if (ISCSIT_MAX_VERSION >= lh_req->min_version) { 874a6d42e7dSPeter Dunlap lh_resp->active_version = 875a6d42e7dSPeter Dunlap MIN(lh_req->max_version, ISCSIT_MAX_VERSION); 876a6d42e7dSPeter Dunlap } else { 877a6d42e7dSPeter Dunlap ASSERT(ISCSIT_MAX_VERSION <= lh_req->max_version); 878a6d42e7dSPeter Dunlap lh_resp->active_version = ISCSIT_MAX_VERSION; 879a6d42e7dSPeter Dunlap } 880a6d42e7dSPeter Dunlap #endif 881a6d42e7dSPeter Dunlap 882a6d42e7dSPeter Dunlap lh_resp->hlength = 0; /* No AHS */ 883a6d42e7dSPeter Dunlap bcopy(lh_req->isid, lh_resp->isid, ISCSI_ISID_LEN); 884a6d42e7dSPeter Dunlap lh_resp->tsid = lh_req->tsid; 885a6d42e7dSPeter Dunlap lh_resp->itt = lh_req->itt; 886a6d42e7dSPeter Dunlap 887a6d42e7dSPeter Dunlap /* 888a6d42e7dSPeter Dunlap * StatSn, ExpCmdSn and MaxCmdSn will be set immediately before 889a6d42e7dSPeter Dunlap * transmission 890a6d42e7dSPeter Dunlap */ 891a6d42e7dSPeter Dunlap } 892a6d42e7dSPeter Dunlap 893a6d42e7dSPeter Dunlap static void 8944142b486SJames Moore login_sm_send_next_response(iscsit_conn_t *ict, idm_pdu_t *pdu) 895a6d42e7dSPeter Dunlap { 896a6d42e7dSPeter Dunlap iscsi_login_rsp_hdr_t *lh_resp = (iscsi_login_rsp_hdr_t *)pdu->isp_hdr; 897a6d42e7dSPeter Dunlap 8984142b486SJames Moore /* Make sure this PDU is part of the login phase */ 899a6d42e7dSPeter Dunlap ASSERT((pdu->isp_flags & IDM_PDU_LOGIN_TX) != 0); 900a6d42e7dSPeter Dunlap 901a6d42e7dSPeter Dunlap /* 902a6d42e7dSPeter Dunlap * Fill in header values 903a6d42e7dSPeter Dunlap */ 904a6d42e7dSPeter Dunlap hton24(lh_resp->dlength, pdu->isp_datalen); 905a6d42e7dSPeter Dunlap 906a6d42e7dSPeter Dunlap /* 90760220f10SPriya Krishnan * If the login is successful, this login response will contain 90860220f10SPriya Krishnan * the next StatSN and advance the StatSN for the connection. 909a6d42e7dSPeter Dunlap */ 910a6d42e7dSPeter Dunlap if (lh_resp->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 911a6d42e7dSPeter Dunlap ASSERT(ict->ict_sess != NULL); 912a6d42e7dSPeter Dunlap 913a6d42e7dSPeter Dunlap if ((lh_resp->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 914a6d42e7dSPeter Dunlap (ISCSI_LOGIN_NEXT_STAGE(lh_resp->flags) == 915a6d42e7dSPeter Dunlap ISCSI_FULL_FEATURE_PHASE) && 916a6d42e7dSPeter Dunlap !(lh_resp->flags & ISCSI_FLAG_LOGIN_CONTINUE)) { 9174142b486SJames Moore iscsit_login_sm_event(ict, ILE_LOGIN_FFP, NULL); 9184142b486SJames Moore } 9194142b486SJames Moore if (login_sm_is_last_response(pdu) == B_TRUE) { 9204142b486SJames Moore /* 9214142b486SJames Moore * The last of a potentially mult-PDU response finished. 9224142b486SJames Moore */ 9234142b486SJames Moore iscsit_login_sm_event(ict, ILE_LOGIN_RESP_COMPLETE, 9244142b486SJames Moore NULL); 925a6d42e7dSPeter Dunlap } 926a6d42e7dSPeter Dunlap 9274142b486SJames Moore iscsit_conn_hold(ict); 92860220f10SPriya Krishnan pdu->isp_flags |= IDM_PDU_SET_STATSN | IDM_PDU_ADVANCE_STATSN; 929a6d42e7dSPeter Dunlap iscsit_pdu_tx(pdu); 930a6d42e7dSPeter Dunlap } else { 931a6d42e7dSPeter Dunlap /* 932a6d42e7dSPeter Dunlap * If status_class != ISCSI_STATUS_CLASS_SUCCESS then 933a6d42e7dSPeter Dunlap * StatSN is not valid and we can call idm_pdu_tx instead 934a6d42e7dSPeter Dunlap * of iscsit_pdu_tx. This is very good thing since in 935a6d42e7dSPeter Dunlap * some cases of login failure we may not have a session. 936a6d42e7dSPeter Dunlap * Since iscsit_calc_rspsn grabs the session mutex while 937a6d42e7dSPeter Dunlap * it is retrieving values for expcmdsn and maxcmdsn this 938a6d42e7dSPeter Dunlap * would cause a panic. 939a6d42e7dSPeter Dunlap * 940a6d42e7dSPeter Dunlap * Since we still want a value for expcmdsn, fill in an 941a6d42e7dSPeter Dunlap * appropriate value based on the login request before 9421050fd6dSJames Moore * sending the response. Cmdsn/expcmdsn do not advance during 9431050fd6dSJames Moore * login phase. 944a6d42e7dSPeter Dunlap */ 9451050fd6dSJames Moore lh_resp->expcmdsn = htonl(ict->ict_login_sm.icl_cmdsn); 9461050fd6dSJames Moore lh_resp->maxcmdsn = htonl(ict->ict_login_sm.icl_cmdsn + 1); 947a6d42e7dSPeter Dunlap 9484142b486SJames Moore iscsit_conn_hold(ict); 9494142b486SJames Moore idm_pdu_tx(pdu); 950a6d42e7dSPeter Dunlap } 951a6d42e7dSPeter Dunlap 952a6d42e7dSPeter Dunlap } 953a6d42e7dSPeter Dunlap 954a6d42e7dSPeter Dunlap static void 955a6d42e7dSPeter Dunlap login_sm_process_request(iscsit_conn_t *ict) 956a6d42e7dSPeter Dunlap { 957a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 958a6d42e7dSPeter Dunlap uint8_t error_class = 0; 959a6d42e7dSPeter Dunlap uint8_t error_detail = 0; 960a6d42e7dSPeter Dunlap 961a6d42e7dSPeter Dunlap /* 962a6d42e7dSPeter Dunlap * First walk all the PDU's that make up this login request 963a6d42e7dSPeter Dunlap * and compile all the iSCSI key-value pairs into nvlist format. 964a6d42e7dSPeter Dunlap */ 965a6d42e7dSPeter Dunlap 966a6d42e7dSPeter Dunlap ASSERT(lsm->icl_request_nvlist == NULL); 967a6d42e7dSPeter Dunlap /* create an nvlist for request key/value pairs */ 968a6d42e7dSPeter Dunlap if (idm_pdu_list_to_nvlist(&lsm->icl_pdu_list, 969a6d42e7dSPeter Dunlap &lsm->icl_request_nvlist, &error_detail) != IDM_STATUS_SUCCESS) { 970a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_TARGET_ERR; 971a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 972a6d42e7dSPeter Dunlap goto request_fail; 973a6d42e7dSPeter Dunlap } 974a6d42e7dSPeter Dunlap 975a6d42e7dSPeter Dunlap /* Allocate a new nvlist for response key/value pairs */ 976a6d42e7dSPeter Dunlap ASSERT(lsm->icl_response_nvlist == NULL); 977a6d42e7dSPeter Dunlap if (nvlist_alloc(&lsm->icl_response_nvlist, NV_UNIQUE_NAME, 978a6d42e7dSPeter Dunlap KM_NOSLEEP) != 0) { 979a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_TARGET_ERR; 980a6d42e7dSPeter Dunlap error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES; 981a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 982a6d42e7dSPeter Dunlap goto request_fail; 983a6d42e7dSPeter Dunlap } 984a6d42e7dSPeter Dunlap 985a6d42e7dSPeter Dunlap /* 986a6d42e7dSPeter Dunlap * This would be a very good time to make sure we have 987a6d42e7dSPeter Dunlap * negotiated the required values for the login phase. For 988a6d42e7dSPeter Dunlap * example we definitely should have defined InitiatorName, 989a6d42e7dSPeter Dunlap * and Target name regardless of our current login phase. 990a6d42e7dSPeter Dunlap */ 991a6d42e7dSPeter Dunlap if (!ict->ict_op.op_initial_params_set) { 992a6d42e7dSPeter Dunlap if (login_sm_validate_initial_parameters(ict) != 993a6d42e7dSPeter Dunlap IDM_STATUS_SUCCESS) { 994a6d42e7dSPeter Dunlap goto request_fail; 995a6d42e7dSPeter Dunlap } 996a6d42e7dSPeter Dunlap 997a6d42e7dSPeter Dunlap /* 998a6d42e7dSPeter Dunlap * Now setup our session association. This includes 999a6d42e7dSPeter Dunlap * create a new session or looking up an existing session, 1000a6d42e7dSPeter Dunlap * and if this is not a discovery session then we will 1001a6d42e7dSPeter Dunlap * also register this session with STMF. 1002a6d42e7dSPeter Dunlap */ 1003a6d42e7dSPeter Dunlap if (login_sm_session_bind(ict) != IDM_STATUS_SUCCESS) { 1004a6d42e7dSPeter Dunlap goto request_fail; 1005a6d42e7dSPeter Dunlap } 1006a6d42e7dSPeter Dunlap 1007a6d42e7dSPeter Dunlap if (login_sm_set_auth(ict) != IDM_STATUS_SUCCESS) { 1008a6d42e7dSPeter Dunlap goto request_fail; 1009a6d42e7dSPeter Dunlap } 1010a6d42e7dSPeter Dunlap 1011a6d42e7dSPeter Dunlap /* 1012a6d42e7dSPeter Dunlap * Prepend TargetAlias and PortalGroupTag 1013a6d42e7dSPeter Dunlap */ 1014a6d42e7dSPeter Dunlap if (ict->ict_op.op_discovery_session == B_FALSE) { 1015a6d42e7dSPeter Dunlap if ((lsm->icl_auth.ca_tgt_alias[0]) != '\0') { 1016a6d42e7dSPeter Dunlap (void) iscsit_reply_string(ict, 1017a6d42e7dSPeter Dunlap "TargetAlias", 1018a6d42e7dSPeter Dunlap &lsm->icl_auth.ca_tgt_alias[0]); 1019a6d42e7dSPeter Dunlap } 1020a6d42e7dSPeter Dunlap (void) iscsit_reply_numerical(ict, 1021a6d42e7dSPeter Dunlap "TargetPortalGroupTag", 1022a6d42e7dSPeter Dunlap (uint64_t)lsm->icl_tpgt_tag); 1023a6d42e7dSPeter Dunlap } 1024a6d42e7dSPeter Dunlap 1025a6d42e7dSPeter Dunlap ict->ict_op.op_initial_params_set = B_TRUE; 1026a6d42e7dSPeter Dunlap } 1027a6d42e7dSPeter Dunlap 1028a6d42e7dSPeter Dunlap if (login_sm_process_nvlist(ict) != IDM_STATUS_SUCCESS) { 1029a6d42e7dSPeter Dunlap goto request_fail; 1030a6d42e7dSPeter Dunlap } 1031a6d42e7dSPeter Dunlap 1032a6d42e7dSPeter Dunlap if (login_sm_check_security(ict) != IDM_STATUS_SUCCESS) { 1033a6d42e7dSPeter Dunlap goto request_fail; 1034a6d42e7dSPeter Dunlap } 1035a6d42e7dSPeter Dunlap 10364142b486SJames Moore /* clean up request_nvlist */ 10374142b486SJames Moore if (lsm->icl_request_nvlist != NULL) { 10384142b486SJames Moore nvlist_free(lsm->icl_request_nvlist); 10394142b486SJames Moore lsm->icl_request_nvlist = NULL; 10404142b486SJames Moore } 10414142b486SJames Moore 10424142b486SJames Moore /* convert any responses to textbuf form */ 10434142b486SJames Moore ASSERT(lsm->icl_login_resp_itb == NULL); 10444142b486SJames Moore if (lsm->icl_response_nvlist) { 10454142b486SJames Moore lsm->icl_login_resp_itb = idm_nvlist_to_itextbuf( 10464142b486SJames Moore lsm->icl_response_nvlist); 10474142b486SJames Moore if (lsm->icl_login_resp_itb == NULL) { 10484142b486SJames Moore /* Still need to send the resp so continue */ 10494142b486SJames Moore SET_LOGIN_ERROR(ict, 10504142b486SJames Moore ISCSI_STATUS_CLASS_TARGET_ERR, 10514142b486SJames Moore ISCSI_LOGIN_STATUS_NO_RESOURCES); 10524142b486SJames Moore } 10534142b486SJames Moore /* clean up response_nvlist */ 10544142b486SJames Moore nvlist_free(lsm->icl_response_nvlist); 10554142b486SJames Moore lsm->icl_response_nvlist = NULL; 10564142b486SJames Moore } 10574142b486SJames Moore 10584142b486SJames Moore /* tell the state machine to send the textbuf */ 1059a6d42e7dSPeter Dunlap iscsit_login_sm_event(ict, ILE_LOGIN_RESP_READY, NULL); 10604142b486SJames Moore return; 10614142b486SJames Moore 10624142b486SJames Moore request_fail: 1063a6d42e7dSPeter Dunlap 1064a6d42e7dSPeter Dunlap /* clean up request_nvlist and response_nvlist */ 1065a6d42e7dSPeter Dunlap if (lsm->icl_request_nvlist != NULL) { 1066a6d42e7dSPeter Dunlap nvlist_free(lsm->icl_request_nvlist); 1067a6d42e7dSPeter Dunlap lsm->icl_request_nvlist = NULL; 1068a6d42e7dSPeter Dunlap } 1069a6d42e7dSPeter Dunlap if (lsm->icl_response_nvlist != NULL) { 1070a6d42e7dSPeter Dunlap nvlist_free(lsm->icl_response_nvlist); 1071a6d42e7dSPeter Dunlap lsm->icl_response_nvlist = NULL; 1072a6d42e7dSPeter Dunlap } 1073e2073a1dSCharles Ting /* Make sure we already set the login error */ 1074e2073a1dSCharles Ting if (ict->ict_login_sm.icl_login_resp_err_class == 1075e2073a1dSCharles Ting ISCSI_STATUS_CLASS_SUCCESS) { 1076e2073a1dSCharles Ting SET_LOGIN_ERROR(ict, 1077e2073a1dSCharles Ting ISCSI_STATUS_CLASS_TARGET_ERR, 1078e2073a1dSCharles Ting ISCSI_LOGIN_STATUS_TARGET_ERROR); 1079e2073a1dSCharles Ting } 1080e2073a1dSCharles Ting iscsit_login_sm_event(ict, ILE_LOGIN_RESP_READY, NULL); 1081a6d42e7dSPeter Dunlap } 1082a6d42e7dSPeter Dunlap 1083a6d42e7dSPeter Dunlap 1084a6d42e7dSPeter Dunlap static void 1085a6d42e7dSPeter Dunlap login_sm_ffp_actions(iscsit_conn_t *ict) 1086a6d42e7dSPeter Dunlap { 1087a6d42e7dSPeter Dunlap iscsit_process_negotiated_values(ict); 1088a6d42e7dSPeter Dunlap } 1089a6d42e7dSPeter Dunlap 1090a6d42e7dSPeter Dunlap static idm_status_t 1091a6d42e7dSPeter Dunlap login_sm_validate_initial_parameters(iscsit_conn_t *ict) 1092a6d42e7dSPeter Dunlap { 1093a6d42e7dSPeter Dunlap int nvrc; 1094a6d42e7dSPeter Dunlap char *string_val; 10951ef61828SYuri Pankov char *u8_iscsi_name; 10961ef61828SYuri Pankov size_t u8_iscsi_name_len; 1097a6d42e7dSPeter Dunlap uint8_t error_class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 1098a6d42e7dSPeter Dunlap uint8_t error_detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS; 1099a6d42e7dSPeter Dunlap idm_status_t status = IDM_STATUS_FAIL; 1100a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1101a6d42e7dSPeter Dunlap 1102a6d42e7dSPeter Dunlap /* 1103a6d42e7dSPeter Dunlap * Make sure we received the required information from the initial 1104a6d42e7dSPeter Dunlap * login. Add these declaratives to the negotiated list and 1105a6d42e7dSPeter Dunlap * remove them from the request list as we go. If anything fails, 1106a6d42e7dSPeter Dunlap * the caller will clean-up the nvlists. 1107a6d42e7dSPeter Dunlap */ 1108a6d42e7dSPeter Dunlap 1109a6d42e7dSPeter Dunlap /* 1110a6d42e7dSPeter Dunlap * Initiator name 1111a6d42e7dSPeter Dunlap */ 1112a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_string(lsm->icl_request_nvlist, 1113a6d42e7dSPeter Dunlap "InitiatorName", &string_val)) != 0) { 1114a6d42e7dSPeter Dunlap goto initial_params_done; 1115a6d42e7dSPeter Dunlap } 11161ef61828SYuri Pankov 11171ef61828SYuri Pankov u8_iscsi_name = iscsit_fold_name(string_val, &u8_iscsi_name_len); 11181ef61828SYuri Pankov if (u8_iscsi_name == NULL) 1119a6d42e7dSPeter Dunlap goto initial_params_done; 11201ef61828SYuri Pankov nvrc = nvlist_add_string(lsm->icl_negotiated_values, "InitiatorName", 11211ef61828SYuri Pankov u8_iscsi_name); 11221ef61828SYuri Pankov kmem_free(u8_iscsi_name, u8_iscsi_name_len); 11231ef61828SYuri Pankov if (nvrc != 0) 11241ef61828SYuri Pankov goto initial_params_done; 11251ef61828SYuri Pankov 1126a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_string(lsm->icl_negotiated_values, 1127a6d42e7dSPeter Dunlap "InitiatorName", &string_val)) != 0) { 1128a6d42e7dSPeter Dunlap goto initial_params_done; 1129a6d42e7dSPeter Dunlap } 1130a6d42e7dSPeter Dunlap lsm->icl_initiator_name = string_val; 1131a668b114SPriya Krishnan idm_conn_set_initiator_name(ict->ict_ic, lsm->icl_initiator_name); 1132a6d42e7dSPeter Dunlap if ((nvrc = nvlist_remove(lsm->icl_request_nvlist, 1133a6d42e7dSPeter Dunlap "InitiatorName", DATA_TYPE_STRING)) != 0) { 1134a6d42e7dSPeter Dunlap goto initial_params_done; 1135a6d42e7dSPeter Dunlap } 1136a6d42e7dSPeter Dunlap 1137a6d42e7dSPeter Dunlap /* 1138a6d42e7dSPeter Dunlap * Session type 1139a6d42e7dSPeter Dunlap */ 1140a6d42e7dSPeter Dunlap ict->ict_op.op_discovery_session = B_FALSE; 1141a6d42e7dSPeter Dunlap nvrc = nvlist_lookup_string(lsm->icl_request_nvlist, 1142a6d42e7dSPeter Dunlap "SessionType", &string_val); 1143a6d42e7dSPeter Dunlap if (nvrc != ENOENT && nvrc != 0) { 1144a6d42e7dSPeter Dunlap goto initial_params_done; 1145a6d42e7dSPeter Dunlap } 1146a6d42e7dSPeter Dunlap if (nvrc == 0) { 1147a6d42e7dSPeter Dunlap if (strcmp(string_val, "Discovery") == 0) { 1148a6d42e7dSPeter Dunlap ict->ict_op.op_discovery_session = B_TRUE; 1149a6d42e7dSPeter Dunlap } else if (strcmp(string_val, "Normal") != 0) { 1150a6d42e7dSPeter Dunlap goto initial_params_done; 1151a6d42e7dSPeter Dunlap } 1152a6d42e7dSPeter Dunlap if ((nvrc = nvlist_add_string(lsm->icl_negotiated_values, 1153a6d42e7dSPeter Dunlap "SessionType", string_val)) != 0) { 1154a6d42e7dSPeter Dunlap goto initial_params_done; 1155a6d42e7dSPeter Dunlap } 1156a6d42e7dSPeter Dunlap if ((nvrc = nvlist_remove(lsm->icl_request_nvlist, 1157a6d42e7dSPeter Dunlap "SessionType", DATA_TYPE_STRING)) != 0) { 1158a6d42e7dSPeter Dunlap goto initial_params_done; 1159a6d42e7dSPeter Dunlap } 1160a6d42e7dSPeter Dunlap } 1161a6d42e7dSPeter Dunlap 1162a6d42e7dSPeter Dunlap /* 1163a6d42e7dSPeter Dunlap * Must have either TargetName or SessionType==Discovery 1164a6d42e7dSPeter Dunlap */ 1165a6d42e7dSPeter Dunlap lsm->icl_target_name = NULL; 1166a6d42e7dSPeter Dunlap nvrc = nvlist_lookup_string(lsm->icl_request_nvlist, 1167a6d42e7dSPeter Dunlap "TargetName", &string_val); 1168a6d42e7dSPeter Dunlap if (nvrc != ENOENT && nvrc != 0) { 1169a6d42e7dSPeter Dunlap goto initial_params_done; 1170a6d42e7dSPeter Dunlap } 1171a6d42e7dSPeter Dunlap if (nvrc == 0) { 11721ef61828SYuri Pankov u8_iscsi_name = iscsit_fold_name(string_val, 11731ef61828SYuri Pankov &u8_iscsi_name_len); 11741ef61828SYuri Pankov if (u8_iscsi_name == NULL) 11751ef61828SYuri Pankov goto initial_params_done; 11761ef61828SYuri Pankov nvrc = nvlist_add_string(lsm->icl_negotiated_values, 11771ef61828SYuri Pankov "TargetName", u8_iscsi_name); 11781ef61828SYuri Pankov kmem_free(u8_iscsi_name, u8_iscsi_name_len); 11791ef61828SYuri Pankov if (nvrc != 0) 1180a6d42e7dSPeter Dunlap goto initial_params_done; 1181a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_string(lsm->icl_negotiated_values, 1182a6d42e7dSPeter Dunlap "TargetName", &string_val)) != 0) { 1183a6d42e7dSPeter Dunlap goto initial_params_done; 1184a6d42e7dSPeter Dunlap } 1185a6d42e7dSPeter Dunlap lsm->icl_target_name = string_val; 1186a668b114SPriya Krishnan idm_conn_set_target_name(ict->ict_ic, lsm->icl_target_name); 1187a6d42e7dSPeter Dunlap if ((nvrc = nvlist_remove(lsm->icl_request_nvlist, 1188a6d42e7dSPeter Dunlap "TargetName", DATA_TYPE_STRING)) != 0) { 1189a6d42e7dSPeter Dunlap goto initial_params_done; 1190a6d42e7dSPeter Dunlap } 1191a6d42e7dSPeter Dunlap } else if (ict->ict_op.op_discovery_session == B_FALSE) { 1192a6d42e7dSPeter Dunlap /* 1193a6d42e7dSPeter Dunlap * Missing target name 1194a6d42e7dSPeter Dunlap */ 1195a6d42e7dSPeter Dunlap goto initial_params_done; 1196a6d42e7dSPeter Dunlap } 1197a6d42e7dSPeter Dunlap 1198a668b114SPriya Krishnan idm_conn_set_isid(ict->ict_ic, lsm->icl_isid); 1199a668b114SPriya Krishnan (void) snprintf(ict->ict_ic->ic_tsih, ISCSI_MAX_TSIH_LEN + 1, "0x%04x", 1200a668b114SPriya Krishnan lsm->icl_tsih); 1201a668b114SPriya Krishnan 1202a6d42e7dSPeter Dunlap IDM_SM_LOG(CE_NOTE, "conn %p: initiator=%s", (void *)ict->ict_ic, 1203a6d42e7dSPeter Dunlap (lsm->icl_initiator_name == NULL) ? "N/A" : 1204a6d42e7dSPeter Dunlap lsm->icl_initiator_name); 1205a6d42e7dSPeter Dunlap IDM_SM_LOG(CE_NOTE, "conn %p: target=%s", (void *)ict->ict_ic, 1206a6d42e7dSPeter Dunlap (lsm->icl_target_name == NULL) ? "N/A" : 1207a6d42e7dSPeter Dunlap lsm->icl_target_name); 1208a6d42e7dSPeter Dunlap IDM_SM_LOG(CE_NOTE, "conn %p: sessiontype=%s", (void *)ict->ict_ic, 1209a6d42e7dSPeter Dunlap ict->ict_op.op_discovery_session ? "Discovery" : "Normal"); 1210a6d42e7dSPeter Dunlap 1211a6d42e7dSPeter Dunlap /* Sucess */ 1212a6d42e7dSPeter Dunlap status = IDM_STATUS_SUCCESS; 1213a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_SUCCESS; 1214a6d42e7dSPeter Dunlap error_detail = ISCSI_LOGIN_STATUS_ACCEPT; 1215a6d42e7dSPeter Dunlap 1216a6d42e7dSPeter Dunlap initial_params_done: 1217a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 1218a6d42e7dSPeter Dunlap return (status); 1219a6d42e7dSPeter Dunlap } 1220a6d42e7dSPeter Dunlap 1221a6d42e7dSPeter Dunlap 1222a6d42e7dSPeter Dunlap /* 1223a6d42e7dSPeter Dunlap * login_sm_session_bind 1224a6d42e7dSPeter Dunlap * 1225a6d42e7dSPeter Dunlap * This function looks at the data from the initial login request 1226a6d42e7dSPeter Dunlap * of a new connection and either looks up and existing session, 1227a6d42e7dSPeter Dunlap * creates a new session, or returns an error. RFC3720 section 5.3.1 1228a6d42e7dSPeter Dunlap * defines these rules: 1229a6d42e7dSPeter Dunlap * 1230a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1231a6d42e7dSPeter Dunlap * |ISID | TSIH | CID | Target action | 1232a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1233a6d42e7dSPeter Dunlap * |new | non-zero | any | fail the login | 1234a6d42e7dSPeter Dunlap * | | | | ("session does not exist") | 1235a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1236a6d42e7dSPeter Dunlap * |new | zero | any | instantiate a new session | 1237a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1238a6d42e7dSPeter Dunlap * |existing | zero | any | do session reinstatement | 1239a6d42e7dSPeter Dunlap * | | | | (see section 5.3.5) | 1240a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1241a6d42e7dSPeter Dunlap * |existing | non-zero | new | add a new connection to | 1242a6d42e7dSPeter Dunlap * | | existing | | the session | 1243a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1244a6d42e7dSPeter Dunlap * |existing | non-zero |existing| do connection reinstatement| 1245a6d42e7dSPeter Dunlap * | | existing | | (see section 5.3.4) | 1246a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1247a6d42e7dSPeter Dunlap * |existing | non-zero | any | fail the login | 1248a6d42e7dSPeter Dunlap * | | new | | ("session does not exist") | 1249a6d42e7dSPeter Dunlap * +------------------------------------------------------------------+ 1250a6d42e7dSPeter Dunlap * 1251a6d42e7dSPeter Dunlap */ 1252a6d42e7dSPeter Dunlap 1253a6d42e7dSPeter Dunlap /* 1254a6d42e7dSPeter Dunlap * Map an <ipv6,port> address to an <ipv4,port> address if possible. 1255a6d42e7dSPeter Dunlap * Returns: 1256a6d42e7dSPeter Dunlap * 1 - success 1257a6d42e7dSPeter Dunlap * 0 - address not mapable 1258a6d42e7dSPeter Dunlap */ 1259a6d42e7dSPeter Dunlap 1260483b029bSYuri Pankov int 1261a6d42e7dSPeter Dunlap iscsit_is_v4_mapped(struct sockaddr_storage *sa, struct sockaddr_storage *v4sa) 1262a6d42e7dSPeter Dunlap { 1263a6d42e7dSPeter Dunlap struct sockaddr_in *sin; 1264a6d42e7dSPeter Dunlap struct in_addr *in; 1265a6d42e7dSPeter Dunlap struct sockaddr_in6 *sin6; 1266a6d42e7dSPeter Dunlap struct in6_addr *in6; 1267a6d42e7dSPeter Dunlap int ret = 0; 1268a6d42e7dSPeter Dunlap 1269a6d42e7dSPeter Dunlap sin6 = (struct sockaddr_in6 *)sa; 1270a6d42e7dSPeter Dunlap in6 = &sin6->sin6_addr; 1271a6d42e7dSPeter Dunlap if ((sa->ss_family == AF_INET6) && 1272a6d42e7dSPeter Dunlap (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6))) { 1273a6d42e7dSPeter Dunlap sin = (struct sockaddr_in *)v4sa; 1274a6d42e7dSPeter Dunlap in = &sin->sin_addr; 1275a6d42e7dSPeter Dunlap v4sa->ss_family = AF_INET; 1276a6d42e7dSPeter Dunlap sin->sin_port = sin6->sin6_port; 1277a6d42e7dSPeter Dunlap IN6_V4MAPPED_TO_INADDR(in6, in); 1278a6d42e7dSPeter Dunlap ret = 1; 1279a6d42e7dSPeter Dunlap } 1280a6d42e7dSPeter Dunlap return (ret); 1281a6d42e7dSPeter Dunlap } 1282a6d42e7dSPeter Dunlap 1283a6d42e7dSPeter Dunlap static idm_status_t 1284a6d42e7dSPeter Dunlap login_sm_session_bind(iscsit_conn_t *ict) 1285a6d42e7dSPeter Dunlap { 1286a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1287a6d42e7dSPeter Dunlap iscsit_tgt_t *tgt = NULL; 1288a6d42e7dSPeter Dunlap iscsit_tpgt_t *tpgt = NULL; 1289a6d42e7dSPeter Dunlap iscsit_portal_t *portal = NULL; 1290a6d42e7dSPeter Dunlap iscsit_sess_t *existing_sess = NULL; 1291a6d42e7dSPeter Dunlap iscsit_sess_t *new_sess = NULL; 1292a6d42e7dSPeter Dunlap iscsit_conn_t *existing_ict = NULL; 1293a6d42e7dSPeter Dunlap uint8_t error_class; 1294a6d42e7dSPeter Dunlap uint8_t error_detail; 1295a6d42e7dSPeter Dunlap 12963fc1e17eSPriya Krishnan /* 12973fc1e17eSPriya Krishnan * The multi-threaded execution of binding login sessions to target 12983fc1e17eSPriya Krishnan * introduced race conditions in the session creation/binding and 12993fc1e17eSPriya Krishnan * allowed duplicate sessions to tbe created. The addition of the 13003fc1e17eSPriya Krishnan * global mutex login_sm_session_mutex makes this function single 13013fc1e17eSPriya Krishnan * threaded to avoid such race conditions. Although this causes 13023fc1e17eSPriya Krishnan * a small portion of the login to be serialized, it is unlikely 13033fc1e17eSPriya Krishnan * that there would be numerous simultaneous logins to become a 13043fc1e17eSPriya Krishnan * performance issue. 13053fc1e17eSPriya Krishnan */ 13063fc1e17eSPriya Krishnan mutex_enter(&login_sm_session_mutex); 13073fc1e17eSPriya Krishnan 1308a6d42e7dSPeter Dunlap /* 1309a6d42e7dSPeter Dunlap * Look up target and then check if there are sessions or connections 1310a6d42e7dSPeter Dunlap * that match this request (see below). Any holds taken on objects 1311a6d42e7dSPeter Dunlap * must be released at the end of the function (let's keep things 1312a6d42e7dSPeter Dunlap * simple). 1313a6d42e7dSPeter Dunlap * 1314a6d42e7dSPeter Dunlap * If target name is set then we should have a corresponding target 1315a6d42e7dSPeter Dunlap * context configured. 1316a6d42e7dSPeter Dunlap */ 1317a6d42e7dSPeter Dunlap if (lsm->icl_target_name != NULL) { 1318a6d42e7dSPeter Dunlap /* 1319a6d42e7dSPeter Dunlap * iscsit_tgt_lookup implicitly takes a ref on the target 1320a6d42e7dSPeter Dunlap */ 1321a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_LOCK(RW_READER); 1322a6d42e7dSPeter Dunlap tgt = iscsit_tgt_lookup_locked(lsm->icl_target_name); 1323a6d42e7dSPeter Dunlap if (tgt == NULL) { 1324a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1325a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1326a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); 1327a6d42e7dSPeter Dunlap goto session_bind_error; 1328a6d42e7dSPeter Dunlap } else { 1329a6d42e7dSPeter Dunlap mutex_enter(&tgt->target_mutex); 1330a6d42e7dSPeter Dunlap tpgt = avl_first(&tgt->target_tpgt_list); 1331a6d42e7dSPeter Dunlap 1332a6d42e7dSPeter Dunlap if (IS_DEFAULT_TPGT(tpgt)) { 1333a6d42e7dSPeter Dunlap lsm->icl_tpgt_tag = ISCSIT_DEFAULT_TPGT; 1334a6d42e7dSPeter Dunlap } else { 1335a6d42e7dSPeter Dunlap /* 1336a6d42e7dSPeter Dunlap * Find the portal group tag for the 1337a6d42e7dSPeter Dunlap * login response. 1338a6d42e7dSPeter Dunlap */ 1339a6d42e7dSPeter Dunlap struct sockaddr_storage v4sa, *sa; 1340a6d42e7dSPeter Dunlap 1341a6d42e7dSPeter Dunlap sa = &ict->ict_ic->ic_laddr; 1342a6d42e7dSPeter Dunlap portal = iscsit_tgt_lookup_portal(tgt, 1343a6d42e7dSPeter Dunlap sa, &tpgt); 1344a6d42e7dSPeter Dunlap if (portal == NULL && 1345a6d42e7dSPeter Dunlap iscsit_is_v4_mapped(sa, &v4sa)) { 1346a6d42e7dSPeter Dunlap /* 1347a6d42e7dSPeter Dunlap * Try again if the local address 1348a6d42e7dSPeter Dunlap * was v6 mappable to v4. 1349a6d42e7dSPeter Dunlap */ 1350a6d42e7dSPeter Dunlap portal = iscsit_tgt_lookup_portal(tgt, 1351a6d42e7dSPeter Dunlap &v4sa, &tpgt); 1352a6d42e7dSPeter Dunlap 1353a6d42e7dSPeter Dunlap } 1354a6d42e7dSPeter Dunlap if (portal == NULL) { 1355a6d42e7dSPeter Dunlap /* 1356a6d42e7dSPeter Dunlap * Initiator came in on wrong address 1357a6d42e7dSPeter Dunlap */ 1358a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, 1359a6d42e7dSPeter Dunlap ISCSI_STATUS_CLASS_INITIATOR_ERR, 1360a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); 1361a6d42e7dSPeter Dunlap mutex_exit(&tgt->target_mutex); 1362a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1363a6d42e7dSPeter Dunlap goto session_bind_error; 1364a6d42e7dSPeter Dunlap } 1365a6d42e7dSPeter Dunlap 1366a6d42e7dSPeter Dunlap /* 1367a6d42e7dSPeter Dunlap * Need to release holds on the portal and 1368a6d42e7dSPeter Dunlap * tpgt after processing is complete. 1369a6d42e7dSPeter Dunlap */ 1370a6d42e7dSPeter Dunlap lsm->icl_tpgt_tag = tpgt->tpgt_tag; 1371a6d42e7dSPeter Dunlap iscsit_portal_rele(portal); 1372a6d42e7dSPeter Dunlap iscsit_tpgt_rele(tpgt); 1373a6d42e7dSPeter Dunlap } 1374a6d42e7dSPeter Dunlap 13758c629652SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_enter(&iscsit_global.global_state_mutex); 1376a6d42e7dSPeter Dunlap if ((tgt->target_state != TS_STMF_ONLINE) || 1377a6d42e7dSPeter Dunlap ((iscsit_global.global_svc_state != ISE_ENABLED) && 1378a6d42e7dSPeter Dunlap ((iscsit_global.global_svc_state != ISE_BUSY)))) { 13798c629652SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&iscsit_global.global_state_mutex); 1380a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, 138172cf3143Speter dunlap ISCSI_STATUS_CLASS_TARGET_ERR, 138272cf3143Speter dunlap ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); 1383a6d42e7dSPeter Dunlap mutex_exit(&tgt->target_mutex); 1384a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1385a6d42e7dSPeter Dunlap goto session_bind_error; 1386a6d42e7dSPeter Dunlap } 13878c629652SPeter Cudhea - Sun Microsystems - Burlington, MA United States mutex_exit(&iscsit_global.global_state_mutex); 1388a6d42e7dSPeter Dunlap mutex_exit(&tgt->target_mutex); 1389a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1390a6d42e7dSPeter Dunlap } 1391a6d42e7dSPeter Dunlap } 1392a6d42e7dSPeter Dunlap 1393a6d42e7dSPeter Dunlap ASSERT((tgt != NULL) || (ict->ict_op.op_discovery_session == B_TRUE)); 1394a6d42e7dSPeter Dunlap 1395a6d42e7dSPeter Dunlap /* 1396a6d42e7dSPeter Dunlap * Check if there is an existing session matching this ISID. If 1397a6d42e7dSPeter Dunlap * tgt == NULL then we'll look for the session on the global list 1398a6d42e7dSPeter Dunlap * of discovery session. If we find a session then the ISID 1399a6d42e7dSPeter Dunlap * exists. 1400a6d42e7dSPeter Dunlap */ 1401a6d42e7dSPeter Dunlap existing_sess = iscsit_tgt_lookup_sess(tgt, lsm->icl_initiator_name, 1402a6d42e7dSPeter Dunlap lsm->icl_isid, lsm->icl_tsih, lsm->icl_tpgt_tag); 1403a6d42e7dSPeter Dunlap if (existing_sess != NULL) { 1404a6d42e7dSPeter Dunlap existing_ict = iscsit_sess_lookup_conn(existing_sess, 1405a6d42e7dSPeter Dunlap ict->ict_cid); 1406a6d42e7dSPeter Dunlap } 1407a6d42e7dSPeter Dunlap 1408a6d42e7dSPeter Dunlap /* 1409a6d42e7dSPeter Dunlap * If this is a discovery session, make sure it has appropriate 1410a6d42e7dSPeter Dunlap * parameters. 1411a6d42e7dSPeter Dunlap */ 1412a6d42e7dSPeter Dunlap if ((ict->ict_op.op_discovery_session == B_TRUE) && 1413a6d42e7dSPeter Dunlap ((lsm->icl_tsih != ISCSI_UNSPEC_TSIH) || (existing_sess != NULL))) { 1414a6d42e7dSPeter Dunlap /* XXX Do we need to check for existing ISID (sess != NULL)? */ 1415a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1416a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_INVALID_REQUEST); 1417a6d42e7dSPeter Dunlap goto session_bind_error; 1418a6d42e7dSPeter Dunlap } 1419a6d42e7dSPeter Dunlap 1420a6d42e7dSPeter Dunlap /* 1421a6d42e7dSPeter Dunlap * Check the two error conditions from the table. 1422a6d42e7dSPeter Dunlap * 1423a6d42e7dSPeter Dunlap * ISID=new, TSIH=non-zero 1424a6d42e7dSPeter Dunlap */ 1425a6d42e7dSPeter Dunlap if ((existing_sess == NULL) && (lsm->icl_tsih != ISCSI_UNSPEC_TSIH)) { 1426a6d42e7dSPeter Dunlap /* fail the login */ 1427a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1428a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_NO_SESSION); 1429a6d42e7dSPeter Dunlap goto session_bind_error; 1430a6d42e7dSPeter Dunlap } 1431a6d42e7dSPeter Dunlap 1432a6d42e7dSPeter Dunlap /* ISID=existing, TSIH=non-zero new */ 1433a6d42e7dSPeter Dunlap if ((existing_sess != NULL) && (lsm->icl_tsih != 0) && 1434a6d42e7dSPeter Dunlap (existing_sess->ist_tsih != lsm->icl_tsih)) { 1435a6d42e7dSPeter Dunlap /* fail the login */ 1436a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1437a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_NO_SESSION); 1438a6d42e7dSPeter Dunlap goto session_bind_error; 1439a6d42e7dSPeter Dunlap } 1440a6d42e7dSPeter Dunlap 1441a6d42e7dSPeter Dunlap /* 1442a6d42e7dSPeter Dunlap * Handle the remaining table cases in order 1443a6d42e7dSPeter Dunlap */ 1444a6d42e7dSPeter Dunlap if (existing_sess == NULL) { 1445a6d42e7dSPeter Dunlap /* Should have caught this above */ 1446a6d42e7dSPeter Dunlap ASSERT(lsm->icl_tsih == ISCSI_UNSPEC_TSIH); 1447a6d42e7dSPeter Dunlap /* 1448a6d42e7dSPeter Dunlap * ISID=new, TSIH=zero --> instantiate a new session 1449a6d42e7dSPeter Dunlap */ 1450a6d42e7dSPeter Dunlap new_sess = iscsit_sess_create(tgt, ict, lsm->icl_cmdsn, 1451a6d42e7dSPeter Dunlap lsm->icl_isid, lsm->icl_tpgt_tag, lsm->icl_initiator_name, 1452a6d42e7dSPeter Dunlap lsm->icl_target_name, &error_class, &error_detail); 1453a6d42e7dSPeter Dunlap ASSERT(new_sess != NULL); 1454a6d42e7dSPeter Dunlap 1455a6d42e7dSPeter Dunlap /* Session create may have failed even if it returned a value */ 1456a6d42e7dSPeter Dunlap if (error_class != ISCSI_STATUS_CLASS_SUCCESS) { 1457a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 1458a6d42e7dSPeter Dunlap goto session_bind_error; 1459a6d42e7dSPeter Dunlap } 1460a6d42e7dSPeter Dunlap 1461a6d42e7dSPeter Dunlap /* 1462a6d42e7dSPeter Dunlap * If we don't already have an STMF session and this is not 1463a6d42e7dSPeter Dunlap * a discovery session then we need to allocate and register 1464a6d42e7dSPeter Dunlap * one. 1465a6d42e7dSPeter Dunlap */ 1466a6d42e7dSPeter Dunlap if (!ict->ict_op.op_discovery_session) { 1467a6d42e7dSPeter Dunlap if (login_sm_session_register(ict) != 1468a6d42e7dSPeter Dunlap IDM_STATUS_SUCCESS) { 1469a6d42e7dSPeter Dunlap /* login_sm_session_register sets error codes */ 1470a6d42e7dSPeter Dunlap goto session_bind_error; 1471a6d42e7dSPeter Dunlap } 1472a6d42e7dSPeter Dunlap } 1473a6d42e7dSPeter Dunlap 1474a6d42e7dSPeter Dunlap } else { 1475a6d42e7dSPeter Dunlap if (lsm->icl_tsih == ISCSI_UNSPEC_TSIH) { 1476a6d42e7dSPeter Dunlap /* 1477a6d42e7dSPeter Dunlap * ISID=existing, TSIH=zero --> Session reinstatement 1478a6d42e7dSPeter Dunlap */ 1479a6d42e7dSPeter Dunlap new_sess = iscsit_sess_reinstate(tgt, existing_sess, 1480a6d42e7dSPeter Dunlap ict, &error_class, &error_detail); 1481a6d42e7dSPeter Dunlap ASSERT(new_sess != NULL); 1482a6d42e7dSPeter Dunlap 1483a6d42e7dSPeter Dunlap if (error_class != ISCSI_STATUS_CLASS_SUCCESS) { 1484a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 1485a6d42e7dSPeter Dunlap goto session_bind_error; 1486a6d42e7dSPeter Dunlap } 1487a6d42e7dSPeter Dunlap 1488a6d42e7dSPeter Dunlap /* 1489a6d42e7dSPeter Dunlap * If we don't already have an STMF session and this is 1490a6d42e7dSPeter Dunlap * not a discovery session then we need to allocate and 1491a6d42e7dSPeter Dunlap * register one. 1492a6d42e7dSPeter Dunlap */ 1493a6d42e7dSPeter Dunlap if (!ict->ict_op.op_discovery_session) { 1494a6d42e7dSPeter Dunlap if (login_sm_session_register(ict) != 1495a6d42e7dSPeter Dunlap IDM_STATUS_SUCCESS) { 1496a6d42e7dSPeter Dunlap /* 1497a6d42e7dSPeter Dunlap * login_sm_session_register sets 1498a6d42e7dSPeter Dunlap * error codes 1499a6d42e7dSPeter Dunlap */ 1500a6d42e7dSPeter Dunlap goto session_bind_error; 1501a6d42e7dSPeter Dunlap } 1502a6d42e7dSPeter Dunlap } 1503a6d42e7dSPeter Dunlap } else { 1504a6d42e7dSPeter Dunlap /* 1505a6d42e7dSPeter Dunlap * The following code covers these two cases: 1506a6d42e7dSPeter Dunlap * ISID=existing, TSIH=non-zero existing, CID=new 1507a6d42e7dSPeter Dunlap * --> add new connection to MC/S session 1508a6d42e7dSPeter Dunlap * ISID=existing, TSIH=non-zero existing, CID=existing 1509a6d42e7dSPeter Dunlap * --> do connection reinstatement 1510a6d42e7dSPeter Dunlap * 1511a6d42e7dSPeter Dunlap * Session continuation uses this path as well 1512a6d42e7dSPeter Dunlap */ 1513a6d42e7dSPeter Dunlap cmn_err(CE_NOTE, "login_sm_session_bind: add new " 1514a6d42e7dSPeter Dunlap "conn/sess continue"); 1515a6d42e7dSPeter Dunlap if (existing_ict != NULL) { 1516a6d42e7dSPeter Dunlap /* 1517a6d42e7dSPeter Dunlap * ISID=existing, TSIH=non-zero existing, 1518a6d42e7dSPeter Dunlap * CID=existing --> do connection reinstatement 1519a6d42e7dSPeter Dunlap */ 1520a6d42e7dSPeter Dunlap if (iscsit_conn_reinstate(existing_ict, ict) != 1521a6d42e7dSPeter Dunlap IDM_STATUS_SUCCESS) { 1522a6d42e7dSPeter Dunlap /* 1523a6d42e7dSPeter Dunlap * Most likely this means the connection 1524a6d42e7dSPeter Dunlap * the initiator is trying to reinstate 1525a6d42e7dSPeter Dunlap * is not in an acceptable state. 1526a6d42e7dSPeter Dunlap */ 1527a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, 1528a6d42e7dSPeter Dunlap ISCSI_STATUS_CLASS_INITIATOR_ERR, 1529a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_INIT_ERR); 1530a6d42e7dSPeter Dunlap goto session_bind_error; 1531a6d42e7dSPeter Dunlap } 1532a6d42e7dSPeter Dunlap } 1533a6d42e7dSPeter Dunlap 1534a6d42e7dSPeter Dunlap iscsit_sess_sm_event(existing_sess, SE_CONN_IN_LOGIN, 1535a6d42e7dSPeter Dunlap ict); 1536a6d42e7dSPeter Dunlap } 1537a6d42e7dSPeter Dunlap } 1538a6d42e7dSPeter Dunlap 1539a6d42e7dSPeter Dunlap if (tgt != NULL) 1540a6d42e7dSPeter Dunlap iscsit_tgt_rele(tgt); 1541a6d42e7dSPeter Dunlap if (existing_sess != NULL) 1542a6d42e7dSPeter Dunlap iscsit_sess_rele(existing_sess); 1543a6d42e7dSPeter Dunlap if (existing_ict != NULL) 1544a6d42e7dSPeter Dunlap iscsit_conn_rele(existing_ict); 1545a6d42e7dSPeter Dunlap 15463fc1e17eSPriya Krishnan mutex_exit(&login_sm_session_mutex); 1547a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1548a6d42e7dSPeter Dunlap 1549a6d42e7dSPeter Dunlap session_bind_error: 1550a6d42e7dSPeter Dunlap if (tgt != NULL) 1551a6d42e7dSPeter Dunlap iscsit_tgt_rele(tgt); 1552a6d42e7dSPeter Dunlap if (existing_sess != NULL) 1553a6d42e7dSPeter Dunlap iscsit_sess_rele(existing_sess); 1554a6d42e7dSPeter Dunlap if (existing_ict != NULL) 1555a6d42e7dSPeter Dunlap iscsit_conn_rele(existing_ict); 1556a6d42e7dSPeter Dunlap 1557a6d42e7dSPeter Dunlap /* 1558a6d42e7dSPeter Dunlap * If session bind fails we will fail the login but don't destroy 1559a6d42e7dSPeter Dunlap * the session until later. 1560a6d42e7dSPeter Dunlap */ 15613fc1e17eSPriya Krishnan mutex_exit(&login_sm_session_mutex); 1562a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1563a6d42e7dSPeter Dunlap } 1564a6d42e7dSPeter Dunlap 1565a6d42e7dSPeter Dunlap 1566a6d42e7dSPeter Dunlap static idm_status_t 1567a6d42e7dSPeter Dunlap login_sm_set_auth(iscsit_conn_t *ict) 1568a6d42e7dSPeter Dunlap { 1569a6d42e7dSPeter Dunlap idm_status_t idmrc = IDM_STATUS_SUCCESS; 1570a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1571a6d42e7dSPeter Dunlap iscsit_ini_t *ini; 1572a6d42e7dSPeter Dunlap iscsit_tgt_t *tgt; 1573a6d42e7dSPeter Dunlap char *auth = ""; 1574a6d42e7dSPeter Dunlap char *radiusserver = ""; 1575a6d42e7dSPeter Dunlap char *radiussecret = ""; 1576a6d42e7dSPeter Dunlap char *chapuser = ""; 1577a6d42e7dSPeter Dunlap char *chapsecret = ""; 1578a6d42e7dSPeter Dunlap char *targetchapuser = ""; 1579a6d42e7dSPeter Dunlap char *targetchapsecret = ""; 1580a6d42e7dSPeter Dunlap char *targetalias = ""; 1581a6d42e7dSPeter Dunlap int i; 1582a6d42e7dSPeter Dunlap 1583a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_LOCK(RW_READER); 1584a6d42e7dSPeter Dunlap 1585a6d42e7dSPeter Dunlap /* 1586a6d42e7dSPeter Dunlap * Set authentication method to none for discovery session. 1587a6d42e7dSPeter Dunlap */ 1588a6d42e7dSPeter Dunlap if (ict->ict_op.op_discovery_session == B_TRUE) { 1589a6d42e7dSPeter Dunlap lsm->icl_auth.ca_method_valid_list[0] = AM_NONE; 1590a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1591a6d42e7dSPeter Dunlap return (idmrc); 1592a6d42e7dSPeter Dunlap } 1593a6d42e7dSPeter Dunlap 1594a6d42e7dSPeter Dunlap /* 1595a6d42e7dSPeter Dunlap * Get all the authentication parameters we need -- since we hold 1596a6d42e7dSPeter Dunlap * the global config lock we guarantee that the parameters will 1597a6d42e7dSPeter Dunlap * be consistent with each other. 1598a6d42e7dSPeter Dunlap */ 1599a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(iscsit_global.global_props, 1600a6d42e7dSPeter Dunlap PROP_AUTH, &auth); 1601a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(iscsit_global.global_props, 1602a6d42e7dSPeter Dunlap PROP_RADIUS_SERVER, &radiusserver); 1603a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(iscsit_global.global_props, 1604a6d42e7dSPeter Dunlap PROP_RADIUS_SECRET, &radiussecret); 1605a6d42e7dSPeter Dunlap 1606a6d42e7dSPeter Dunlap ini = iscsit_ini_lookup_locked(lsm->icl_initiator_name); 1607a6d42e7dSPeter Dunlap if (ini != NULL) { 1608a6d42e7dSPeter Dunlap /* Get Initiator CHAP parameters */ 1609a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(ini->ini_props, PROP_CHAP_USER, 1610a6d42e7dSPeter Dunlap &chapuser); 1611a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(ini->ini_props, PROP_CHAP_SECRET, 1612a6d42e7dSPeter Dunlap &chapsecret); 1613a6d42e7dSPeter Dunlap } 1614a6d42e7dSPeter Dunlap 1615a6d42e7dSPeter Dunlap tgt = ict->ict_sess->ist_tgt; 1616a6d42e7dSPeter Dunlap if (tgt != NULL) { 1617a6d42e7dSPeter Dunlap /* See if we have a target-specific authentication setting */ 1618a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(tgt->target_props, PROP_AUTH, 1619a6d42e7dSPeter Dunlap &auth); 1620a6d42e7dSPeter Dunlap /* Get target CHAP parameters */ 1621a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(tgt->target_props, 1622a6d42e7dSPeter Dunlap PROP_TARGET_CHAP_USER, &targetchapuser); 1623a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(tgt->target_props, 1624a6d42e7dSPeter Dunlap PROP_TARGET_CHAP_SECRET, &targetchapsecret); 1625a6d42e7dSPeter Dunlap /* Get alias */ 1626a6d42e7dSPeter Dunlap (void) nvlist_lookup_string(tgt->target_props, 1627a6d42e7dSPeter Dunlap PROP_ALIAS, &targetalias); 1628a6d42e7dSPeter Dunlap } 1629a6d42e7dSPeter Dunlap 1630a6d42e7dSPeter Dunlap /* Set authentication method */ 1631a6d42e7dSPeter Dunlap i = 0; 1632a6d42e7dSPeter Dunlap if (strcmp(auth, PA_AUTH_RADIUS) == 0) { 1633a6d42e7dSPeter Dunlap /* CHAP authentication using RADIUS server */ 1634a6d42e7dSPeter Dunlap lsm->icl_auth.ca_method_valid_list[i++] = AM_CHAP; 1635a6d42e7dSPeter Dunlap lsm->icl_auth.ca_use_radius = B_TRUE; 1636a6d42e7dSPeter Dunlap } else if (strcmp(auth, PA_AUTH_CHAP) == 0) { 1637a6d42e7dSPeter Dunlap /* Local CHAP authentication */ 1638a6d42e7dSPeter Dunlap lsm->icl_auth.ca_method_valid_list[i++] = AM_CHAP; 1639a6d42e7dSPeter Dunlap lsm->icl_auth.ca_use_radius = B_FALSE; 1640a6d42e7dSPeter Dunlap } else if ((strcmp(auth, PA_AUTH_NONE) == 0) || 1641a6d42e7dSPeter Dunlap (strcmp(auth, "") == 0)) { 1642a6d42e7dSPeter Dunlap /* No authentication */ 1643a6d42e7dSPeter Dunlap lsm->icl_auth.ca_method_valid_list[i++] = AM_NONE; 1644a6d42e7dSPeter Dunlap } 1645a6d42e7dSPeter Dunlap 1646a6d42e7dSPeter Dunlap /* 1647a6d42e7dSPeter Dunlap * If initiator/target CHAP username is not set then use the 1648a6d42e7dSPeter Dunlap * node name. If lsm->icl_target_name == NULL then this is 1649a6d42e7dSPeter Dunlap * a discovery session so we don't need to work about the target. 1650a6d42e7dSPeter Dunlap */ 1651a6d42e7dSPeter Dunlap if (strcmp(chapuser, "") == 0) { 1652a6d42e7dSPeter Dunlap (void) strlcpy(lsm->icl_auth.ca_ini_chapuser, 1653a6d42e7dSPeter Dunlap lsm->icl_initiator_name, 165430e7468fSPeter Dunlap min(iscsitAuthStringMaxLength, MAX_ISCSI_NODENAMELEN)); 1655a6d42e7dSPeter Dunlap } else { 1656a6d42e7dSPeter Dunlap (void) strlcpy(lsm->icl_auth.ca_ini_chapuser, chapuser, 165730e7468fSPeter Dunlap iscsitAuthStringMaxLength); 1658a6d42e7dSPeter Dunlap } 1659a6d42e7dSPeter Dunlap if ((lsm->icl_target_name != NULL) && 1660a6d42e7dSPeter Dunlap (strcmp(targetchapuser, "") == 0)) { 1661a6d42e7dSPeter Dunlap (void) strlcpy(lsm->icl_auth.ca_tgt_chapuser, 1662a6d42e7dSPeter Dunlap lsm->icl_target_name, 166330e7468fSPeter Dunlap min(iscsitAuthStringMaxLength, MAX_ISCSI_NODENAMELEN)); 1664a6d42e7dSPeter Dunlap } else { 1665a6d42e7dSPeter Dunlap (void) strlcpy(lsm->icl_auth.ca_tgt_chapuser, 166630e7468fSPeter Dunlap targetchapuser, iscsitAuthStringMaxLength); 1667a6d42e7dSPeter Dunlap } 1668a6d42e7dSPeter Dunlap 1669a6d42e7dSPeter Dunlap /* 1670a6d42e7dSPeter Dunlap * Secrets are stored in base64-encoded format so we need to 1671a6d42e7dSPeter Dunlap * decode them into binary form 1672a6d42e7dSPeter Dunlap */ 1673a6d42e7dSPeter Dunlap if (strcmp(chapsecret, "") == 0) { 1674a6d42e7dSPeter Dunlap lsm->icl_auth.ca_ini_chapsecretlen = 0; 1675a6d42e7dSPeter Dunlap } else { 1676a6d42e7dSPeter Dunlap if (iscsi_base64_str_to_binary(chapsecret, 167730e7468fSPeter Dunlap strnlen(chapsecret, iscsitAuthStringMaxLength), 167830e7468fSPeter Dunlap lsm->icl_auth.ca_ini_chapsecret, iscsitAuthStringMaxLength, 1679a6d42e7dSPeter Dunlap &lsm->icl_auth.ca_ini_chapsecretlen) != 0) { 1680a6d42e7dSPeter Dunlap cmn_err(CE_WARN, "Corrupted CHAP secret" 1681a6d42e7dSPeter Dunlap " for initiator %s", lsm->icl_initiator_name); 1682a6d42e7dSPeter Dunlap lsm->icl_auth.ca_ini_chapsecretlen = 0; 1683a6d42e7dSPeter Dunlap } 1684a6d42e7dSPeter Dunlap } 1685a6d42e7dSPeter Dunlap if (strcmp(targetchapsecret, "") == 0) { 1686a6d42e7dSPeter Dunlap lsm->icl_auth.ca_tgt_chapsecretlen = 0; 1687a6d42e7dSPeter Dunlap } else { 1688a6d42e7dSPeter Dunlap if (iscsi_base64_str_to_binary(targetchapsecret, 168930e7468fSPeter Dunlap strnlen(targetchapsecret, iscsitAuthStringMaxLength), 169030e7468fSPeter Dunlap lsm->icl_auth.ca_tgt_chapsecret, iscsitAuthStringMaxLength, 1691a6d42e7dSPeter Dunlap &lsm->icl_auth.ca_tgt_chapsecretlen) != 0) { 1692a6d42e7dSPeter Dunlap cmn_err(CE_WARN, "Corrupted CHAP secret" 1693a6d42e7dSPeter Dunlap " for target %s", lsm->icl_target_name); 1694a6d42e7dSPeter Dunlap lsm->icl_auth.ca_tgt_chapsecretlen = 0; 1695a6d42e7dSPeter Dunlap } 1696a6d42e7dSPeter Dunlap } 1697a6d42e7dSPeter Dunlap if (strcmp(radiussecret, "") == 0) { 1698a6d42e7dSPeter Dunlap lsm->icl_auth.ca_radius_secretlen = 0; 1699a6d42e7dSPeter Dunlap } else { 1700a6d42e7dSPeter Dunlap if (iscsi_base64_str_to_binary(radiussecret, 170130e7468fSPeter Dunlap strnlen(radiussecret, iscsitAuthStringMaxLength), 170230e7468fSPeter Dunlap lsm->icl_auth.ca_radius_secret, iscsitAuthStringMaxLength, 1703a6d42e7dSPeter Dunlap &lsm->icl_auth.ca_radius_secretlen) != 0) { 1704a6d42e7dSPeter Dunlap cmn_err(CE_WARN, "Corrupted RADIUS secret"); 1705a6d42e7dSPeter Dunlap lsm->icl_auth.ca_radius_secretlen = 0; 1706a6d42e7dSPeter Dunlap } 1707a6d42e7dSPeter Dunlap } 1708a6d42e7dSPeter Dunlap 1709a6d42e7dSPeter Dunlap /* 1710a6d42e7dSPeter Dunlap * Set alias 1711a6d42e7dSPeter Dunlap */ 1712a6d42e7dSPeter Dunlap (void) strlcpy(lsm->icl_auth.ca_tgt_alias, targetalias, 1713a6d42e7dSPeter Dunlap MAX_ISCSI_NODENAMELEN); 1714a6d42e7dSPeter Dunlap 1715a6d42e7dSPeter Dunlap /* 1716a6d42e7dSPeter Dunlap * Now that authentication parameters are setup, validate the parameters 1717a6d42e7dSPeter Dunlap * against the authentication mode 1718a6d42e7dSPeter Dunlap * Decode RADIUS server value int lsm->icl_auth.ca_radius_server 1719a6d42e7dSPeter Dunlap */ 1720a6d42e7dSPeter Dunlap if ((strcmp(auth, PA_AUTH_RADIUS) == 0) && 1721a6d42e7dSPeter Dunlap ((lsm->icl_auth.ca_radius_secretlen == 0) || 1722a6d42e7dSPeter Dunlap (strcmp(radiusserver, "") == 0) || 1723a6d42e7dSPeter Dunlap it_common_convert_sa(radiusserver, 1724a6d42e7dSPeter Dunlap &lsm->icl_auth.ca_radius_server, 1725a6d42e7dSPeter Dunlap DEFAULT_RADIUS_PORT) == NULL)) { 1726a6d42e7dSPeter Dunlap cmn_err(CE_WARN, "RADIUS authentication selected " 1727a6d42e7dSPeter Dunlap "for target %s but RADIUS parameters are not " 1728a6d42e7dSPeter Dunlap "configured.", lsm->icl_target_name); 1729a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_TARGET_ERR, 1730a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_TARGET_ERROR); 1731a6d42e7dSPeter Dunlap idmrc = IDM_STATUS_FAIL; 1732a6d42e7dSPeter Dunlap } else if ((strcmp(auth, PA_AUTH_CHAP) == 0) && 1733a6d42e7dSPeter Dunlap (lsm->icl_auth.ca_ini_chapsecretlen == 0)) { 1734a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1735a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_AUTH_FAILED); 1736a6d42e7dSPeter Dunlap idmrc = IDM_STATUS_FAIL; 1737a6d42e7dSPeter Dunlap } 1738a6d42e7dSPeter Dunlap 1739a6d42e7dSPeter Dunlap ISCSIT_GLOBAL_UNLOCK(); 1740a6d42e7dSPeter Dunlap 1741a6d42e7dSPeter Dunlap return (idmrc); 1742a6d42e7dSPeter Dunlap } 1743a6d42e7dSPeter Dunlap 1744a6d42e7dSPeter Dunlap 1745a6d42e7dSPeter Dunlap static idm_status_t 1746a6d42e7dSPeter Dunlap login_sm_session_register(iscsit_conn_t *ict) 1747a6d42e7dSPeter Dunlap { 1748a6d42e7dSPeter Dunlap iscsit_sess_t *ist = ict->ict_sess; 1749a6d42e7dSPeter Dunlap stmf_scsi_session_t *ss; 1750716c1805SNattuvetty Bhavyan iscsi_transport_id_t *iscsi_tptid; 1751716c1805SNattuvetty Bhavyan uint16_t ident_len, adn_len, tptid_sz; 1752a6d42e7dSPeter Dunlap 1753a6d42e7dSPeter Dunlap /* 1754a6d42e7dSPeter Dunlap * Hold target mutex until we have finished registering with STMF 1755a6d42e7dSPeter Dunlap */ 1756a6d42e7dSPeter Dunlap mutex_enter(&ist->ist_tgt->target_mutex); 1757a6d42e7dSPeter Dunlap if (ist->ist_tgt->target_state != TS_STMF_ONLINE) { 1758a6d42e7dSPeter Dunlap mutex_exit(&ist->ist_tgt->target_mutex); 1759a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_INITIATOR_ERR, 1760a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_TGT_REMOVED); 1761a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1762a6d42e7dSPeter Dunlap } 1763a6d42e7dSPeter Dunlap 1764a6d42e7dSPeter Dunlap ss = stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 1765a6d42e7dSPeter Dunlap 0); 1766a6d42e7dSPeter Dunlap if (ss == NULL) { 1767a6d42e7dSPeter Dunlap mutex_exit(&ist->ist_tgt->target_mutex); 1768a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_TARGET_ERR, 1769a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_NO_RESOURCES); 1770a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1771a6d42e7dSPeter Dunlap } 1772a6d42e7dSPeter Dunlap 1773716c1805SNattuvetty Bhavyan ident_len = strlen(ist->ist_initiator_name) + 1; 1774a6d42e7dSPeter Dunlap ss->ss_rport_id = kmem_zalloc(sizeof (scsi_devid_desc_t) + 1775716c1805SNattuvetty Bhavyan ident_len, KM_SLEEP); 1776a6d42e7dSPeter Dunlap (void) strcpy((char *)ss->ss_rport_id->ident, ist->ist_initiator_name); 1777716c1805SNattuvetty Bhavyan ss->ss_rport_id->ident_length = ident_len - 1; 1778a6d42e7dSPeter Dunlap ss->ss_rport_id->protocol_id = PROTOCOL_iSCSI; 1779a6d42e7dSPeter Dunlap ss->ss_rport_id->piv = 1; 1780a6d42e7dSPeter Dunlap ss->ss_rport_id->code_set = CODE_SET_ASCII; 1781a6d42e7dSPeter Dunlap ss->ss_rport_id->association = ID_IS_TARGET_PORT; 1782a6d42e7dSPeter Dunlap 1783716c1805SNattuvetty Bhavyan /* adn_len should be 4 byte aligned, SPC3 rev 23, section 7.54.6 */ 1784716c1805SNattuvetty Bhavyan adn_len = (ident_len + 3) & ~ 3; 1785716c1805SNattuvetty Bhavyan tptid_sz = sizeof (iscsi_transport_id_t) - 1 + adn_len; 1786716c1805SNattuvetty Bhavyan ss->ss_rport = stmf_remote_port_alloc(tptid_sz); 1787716c1805SNattuvetty Bhavyan ss->ss_rport->rport_tptid->protocol_id = PROTOCOL_iSCSI; 1788716c1805SNattuvetty Bhavyan ss->ss_rport->rport_tptid->format_code = 0; 1789716c1805SNattuvetty Bhavyan iscsi_tptid = (iscsi_transport_id_t *)ss->ss_rport->rport_tptid; 1790716c1805SNattuvetty Bhavyan SCSI_WRITE16(&iscsi_tptid->add_len, adn_len); 1791716c1805SNattuvetty Bhavyan (void) strlcpy((char *)iscsi_tptid->iscsi_name, 1792716c1805SNattuvetty Bhavyan ist->ist_initiator_name, ident_len); 1793716c1805SNattuvetty Bhavyan 1794a6d42e7dSPeter Dunlap ss->ss_lport = ist->ist_lport; 1795a6d42e7dSPeter Dunlap 1796a6d42e7dSPeter Dunlap if (stmf_register_scsi_session(ict->ict_sess->ist_lport, ss) != 1797a6d42e7dSPeter Dunlap STMF_SUCCESS) { 1798a6d42e7dSPeter Dunlap mutex_exit(&ist->ist_tgt->target_mutex); 1799a6d42e7dSPeter Dunlap kmem_free(ss->ss_rport_id, 1800a6d42e7dSPeter Dunlap sizeof (scsi_devid_desc_t) + 1801a6d42e7dSPeter Dunlap strlen(ist->ist_initiator_name) + 1); 1802716c1805SNattuvetty Bhavyan stmf_remote_port_free(ss->ss_rport); 1803a6d42e7dSPeter Dunlap stmf_free(ss); 1804a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, ISCSI_STATUS_CLASS_TARGET_ERR, 1805a6d42e7dSPeter Dunlap ISCSI_LOGIN_STATUS_TARGET_ERROR); 1806a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1807a6d42e7dSPeter Dunlap } 1808a6d42e7dSPeter Dunlap 1809a6d42e7dSPeter Dunlap ss->ss_port_private = ict->ict_sess; 1810a6d42e7dSPeter Dunlap ict->ict_sess->ist_stmf_sess = ss; 1811a6d42e7dSPeter Dunlap mutex_exit(&ist->ist_tgt->target_mutex); 1812a6d42e7dSPeter Dunlap 1813a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1814a6d42e7dSPeter Dunlap } 1815a6d42e7dSPeter Dunlap 1816a6d42e7dSPeter Dunlap 1817a6d42e7dSPeter Dunlap static idm_status_t 1818a6d42e7dSPeter Dunlap login_sm_req_pdu_check(iscsit_conn_t *ict, idm_pdu_t *pdu) 1819a6d42e7dSPeter Dunlap { 1820a6d42e7dSPeter Dunlap uint8_t csg_req; 1821a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1822a6d42e7dSPeter Dunlap iscsi_login_hdr_t *lh = (iscsi_login_hdr_t *)pdu->isp_hdr; 1823a6d42e7dSPeter Dunlap iscsi_login_rsp_hdr_t *lh_resp = lsm->icl_login_resp_tmpl; 1824a6d42e7dSPeter Dunlap 1825a6d42e7dSPeter Dunlap /* 1826a6d42e7dSPeter Dunlap * Check CSG 1827a6d42e7dSPeter Dunlap */ 1828a6d42e7dSPeter Dunlap csg_req = ISCSI_LOGIN_CURRENT_STAGE(lh->flags); 1829a6d42e7dSPeter Dunlap switch (csg_req) { 1830a6d42e7dSPeter Dunlap case ISCSI_SECURITY_NEGOTIATION_STAGE: 1831a6d42e7dSPeter Dunlap case ISCSI_OP_PARMS_NEGOTIATION_STAGE: 1832a6d42e7dSPeter Dunlap if ((csg_req != lsm->icl_login_csg) && 1833a6d42e7dSPeter Dunlap (lsm->icl_login_state != ILS_LOGIN_INIT)) { 1834a6d42e7dSPeter Dunlap /* 1835a6d42e7dSPeter Dunlap * Inappropriate CSG change. Initiator can only 1836a6d42e7dSPeter Dunlap * change CSG after we've responded with the 1837a6d42e7dSPeter Dunlap * transit bit set. If we had responded with 1838a6d42e7dSPeter Dunlap * a CSG change previous we would have updated 1839a6d42e7dSPeter Dunlap * our copy of CSG. 1840a6d42e7dSPeter Dunlap * 1841a6d42e7dSPeter Dunlap * The exception is when we are in ILS_LOGIN_INIT 1842a6d42e7dSPeter Dunlap * state since we haven't determined our initial 1843a6d42e7dSPeter Dunlap * CSG value yet. 1844a6d42e7dSPeter Dunlap */ 1845a6d42e7dSPeter Dunlap goto pdu_check_fail; 1846a6d42e7dSPeter Dunlap } 1847a6d42e7dSPeter Dunlap break; 1848a6d42e7dSPeter Dunlap case ISCSI_FULL_FEATURE_PHASE: 1849a6d42e7dSPeter Dunlap default: 1850a6d42e7dSPeter Dunlap goto pdu_check_fail; 1851a6d42e7dSPeter Dunlap } 1852a6d42e7dSPeter Dunlap 1853a6d42e7dSPeter Dunlap /* 1854a6d42e7dSPeter Dunlap * If this is the first login PDU for a new connection then 1855a6d42e7dSPeter Dunlap * the session will be NULL. 1856a6d42e7dSPeter Dunlap */ 1857a6d42e7dSPeter Dunlap if (ict->ict_sess != NULL) { 1858a6d42e7dSPeter Dunlap /* 1859a6d42e7dSPeter Dunlap * We've already created a session on a previous PDU. Make 1860a6d42e7dSPeter Dunlap * sure this PDU is consistent with what we've already seen 1861a6d42e7dSPeter Dunlap */ 1862a6d42e7dSPeter Dunlap if ((ict->ict_cid != ntohs(lh->cid)) || 1863a6d42e7dSPeter Dunlap (bcmp(ict->ict_sess->ist_isid, lh->isid, 1864a6d42e7dSPeter Dunlap ISCSI_ISID_LEN) != 0)) { 1865a6d42e7dSPeter Dunlap goto pdu_check_fail; 1866a6d42e7dSPeter Dunlap } 1867a6d42e7dSPeter Dunlap } 1868a6d42e7dSPeter Dunlap 1869a6d42e7dSPeter Dunlap /* 1870a6d42e7dSPeter Dunlap * Make sure we are compatible with the version range 1871a6d42e7dSPeter Dunlap */ 1872a6d42e7dSPeter Dunlap #if (ISCSIT_MAX_VERSION > 0) 1873a6d42e7dSPeter Dunlap if ((lh->min_version > ISCSIT_MAX_VERSION) || 1874a6d42e7dSPeter Dunlap (lh->max_version < ISCSIT_MIN_VERSION)) { 1875a6d42e7dSPeter Dunlap goto pdu_check_fail; 1876a6d42e7dSPeter Dunlap } 1877a6d42e7dSPeter Dunlap #endif 1878a6d42e7dSPeter Dunlap 1879a6d42e7dSPeter Dunlap /* 1880a6d42e7dSPeter Dunlap * Just in case the initiator changes things up on us along the way 1881a6d42e7dSPeter Dunlap * check against our active_version -- we can't change the active 1882a6d42e7dSPeter Dunlap * version and the initiator is not *supposed* to change its 1883a6d42e7dSPeter Dunlap * min_version and max_version values so this should never happen. 1884a6d42e7dSPeter Dunlap * Of course we only do this if the response header template has 1885a6d42e7dSPeter Dunlap * been built. 1886a6d42e7dSPeter Dunlap */ 1887a6d42e7dSPeter Dunlap if ((lh_resp->opcode == ISCSI_OP_LOGIN_RSP) && /* header valid */ 1888a6d42e7dSPeter Dunlap ((lh->min_version > lh_resp->active_version) || 1889a6d42e7dSPeter Dunlap (lh->max_version < lh_resp->active_version))) { 1890a6d42e7dSPeter Dunlap goto pdu_check_fail; 1891a6d42e7dSPeter Dunlap } 1892a6d42e7dSPeter Dunlap 1893a6d42e7dSPeter Dunlap return (IDM_STATUS_SUCCESS); 1894a6d42e7dSPeter Dunlap 1895a6d42e7dSPeter Dunlap pdu_check_fail: 1896a6d42e7dSPeter Dunlap return (IDM_STATUS_FAIL); 1897a6d42e7dSPeter Dunlap } 1898a6d42e7dSPeter Dunlap 1899a6d42e7dSPeter Dunlap static idm_status_t 1900a6d42e7dSPeter Dunlap login_sm_process_nvlist(iscsit_conn_t *ict) 1901a6d42e7dSPeter Dunlap { 1902a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1903a6d42e7dSPeter Dunlap char *nvp_name; 1904a6d42e7dSPeter Dunlap nvpair_t *nvp; 1905a6d42e7dSPeter Dunlap nvpair_t *next_nvp; 1906a6d42e7dSPeter Dunlap nvpair_t *negotiated_nvp; 1907a6d42e7dSPeter Dunlap kv_status_t kvrc; 1908a6d42e7dSPeter Dunlap uint8_t error_class; 1909a6d42e7dSPeter Dunlap uint8_t error_detail; 1910a6d42e7dSPeter Dunlap idm_status_t idm_status; 1911a6d42e7dSPeter Dunlap 1912a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_SUCCESS; 1913a6d42e7dSPeter Dunlap error_detail = ISCSI_LOGIN_STATUS_ACCEPT; 1914a6d42e7dSPeter Dunlap 1915a6d42e7dSPeter Dunlap /* First, request that the transport process the list */ 1916a6d42e7dSPeter Dunlap kvrc = idm_negotiate_key_values(ict->ict_ic, lsm->icl_request_nvlist, 1917a6d42e7dSPeter Dunlap lsm->icl_response_nvlist, lsm->icl_negotiated_values); 1918a6d42e7dSPeter Dunlap idm_kvstat_to_error(kvrc, &error_class, &error_detail); 1919a6d42e7dSPeter Dunlap if (error_class != ISCSI_STATUS_CLASS_SUCCESS) { 1920a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 1921a6d42e7dSPeter Dunlap idm_status = IDM_STATUS_FAIL; 1922a6d42e7dSPeter Dunlap return (idm_status); 1923a6d42e7dSPeter Dunlap } 1924a6d42e7dSPeter Dunlap 1925a6d42e7dSPeter Dunlap /* Ensure we clear transit bit if the transport layer has countered */ 1926a6d42e7dSPeter Dunlap if (kvrc == KV_HANDLED_NO_TRANSIT) { 1927a6d42e7dSPeter Dunlap lsm->icl_login_transit = B_FALSE; 1928a6d42e7dSPeter Dunlap } 1929a6d42e7dSPeter Dunlap 193078264421SCharles Ting /* Prepend the declarative params */ 193178264421SCharles Ting if (!ict->ict_op.op_declarative_params_set && 193278264421SCharles Ting lsm->icl_login_csg == ISCSI_OP_PARMS_NEGOTIATION_STAGE) { 193378264421SCharles Ting if (iscsit_add_declarative_keys(ict) != IDM_STATUS_SUCCESS) { 193478264421SCharles Ting idm_status = IDM_STATUS_FAIL; 193578264421SCharles Ting return (idm_status); 193678264421SCharles Ting } 193778264421SCharles Ting ict->ict_op.op_declarative_params_set = B_TRUE; 193878264421SCharles Ting } 193978264421SCharles Ting 1940a6d42e7dSPeter Dunlap /* Now, move on and process the rest of the pairs */ 1941a6d42e7dSPeter Dunlap nvp = nvlist_next_nvpair(lsm->icl_request_nvlist, NULL); 1942a6d42e7dSPeter Dunlap while (nvp != NULL) { 1943a6d42e7dSPeter Dunlap next_nvp = nvlist_next_nvpair(lsm->icl_request_nvlist, nvp); 1944a6d42e7dSPeter Dunlap nvp_name = nvpair_name(nvp); 1945a6d42e7dSPeter Dunlap /* 1946a6d42e7dSPeter Dunlap * If we've already agreed upon a value then make sure this 1947a6d42e7dSPeter Dunlap * is not attempting to change that value. From RFC3270 1948a6d42e7dSPeter Dunlap * section 5.3: 1949a6d42e7dSPeter Dunlap * 1950a6d42e7dSPeter Dunlap * "Neither the initiator nor the target should attempt to 1951a6d42e7dSPeter Dunlap * declare or negotiate a parameter more than once during 1952a6d42e7dSPeter Dunlap * login except for responses to specific keys that 1953a6d42e7dSPeter Dunlap * explicitly allow repeated key declarations (e.g., 1954a6d42e7dSPeter Dunlap * TargetAddress). An attempt to renegotiate/redeclare 1955a6d42e7dSPeter Dunlap * parameters not specifically allowed MUST be detected 1956a6d42e7dSPeter Dunlap * by the initiator and target. If such an attempt is 1957a6d42e7dSPeter Dunlap * detected by the target, the target MUST respond 1958a6d42e7dSPeter Dunlap * with Login reject (initiator error); ..." 1959a6d42e7dSPeter Dunlap */ 1960a6d42e7dSPeter Dunlap if (nvlist_lookup_nvpair(lsm->icl_negotiated_values, 1961a6d42e7dSPeter Dunlap nvp_name, &negotiated_nvp) == 0) { 1962a6d42e7dSPeter Dunlap kvrc = KV_HANDLED; 1963a6d42e7dSPeter Dunlap } else { 1964a6d42e7dSPeter Dunlap kvrc = iscsit_handle_key(ict, nvp, nvp_name); 1965a6d42e7dSPeter Dunlap } 1966a6d42e7dSPeter Dunlap 1967a6d42e7dSPeter Dunlap idm_kvstat_to_error(kvrc, &error_class, &error_detail); 1968a6d42e7dSPeter Dunlap if (error_class != ISCSI_STATUS_CLASS_SUCCESS) { 1969a6d42e7dSPeter Dunlap break; 1970a6d42e7dSPeter Dunlap } 1971a6d42e7dSPeter Dunlap 1972a6d42e7dSPeter Dunlap nvp = next_nvp; 1973a6d42e7dSPeter Dunlap } 1974a6d42e7dSPeter Dunlap 1975a6d42e7dSPeter Dunlap if (error_class == ISCSI_STATUS_CLASS_SUCCESS) { 1976a6d42e7dSPeter Dunlap idm_status = IDM_STATUS_SUCCESS; 1977a6d42e7dSPeter Dunlap } else { 1978a6d42e7dSPeter Dunlap /* supply login class/detail for login errors */ 1979a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 1980a6d42e7dSPeter Dunlap idm_status = IDM_STATUS_FAIL; 1981a6d42e7dSPeter Dunlap } 1982a6d42e7dSPeter Dunlap 1983a6d42e7dSPeter Dunlap return (idm_status); 1984a6d42e7dSPeter Dunlap } 1985a6d42e7dSPeter Dunlap 1986a6d42e7dSPeter Dunlap static idm_status_t 1987a6d42e7dSPeter Dunlap login_sm_check_security(iscsit_conn_t *ict) 1988a6d42e7dSPeter Dunlap { 1989a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 1990a6d42e7dSPeter Dunlap conn_auth_t *auth = &lsm->icl_auth; 1991a6d42e7dSPeter Dunlap iscsit_auth_method_t *am_list = &auth->ca_method_valid_list[0]; 1992a6d42e7dSPeter Dunlap kv_status_t kvrc; 1993a6d42e7dSPeter Dunlap uint8_t error_class; 1994a6d42e7dSPeter Dunlap uint8_t error_detail; 1995a6d42e7dSPeter Dunlap idm_status_t idm_status; 1996a6d42e7dSPeter Dunlap 1997a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_SUCCESS; 1998a6d42e7dSPeter Dunlap error_detail = ISCSI_LOGIN_STATUS_ACCEPT; 1999a6d42e7dSPeter Dunlap 2000a6d42e7dSPeter Dunlap /* Check authentication status. */ 2001a6d42e7dSPeter Dunlap if (lsm->icl_login_csg == ISCSI_SECURITY_NEGOTIATION_STAGE) { 2002a6d42e7dSPeter Dunlap /* 2003a6d42e7dSPeter Dunlap * We should have some authentication key/value pair(s) 2004a6d42e7dSPeter Dunlap * received from initiator and the authentication phase 2005a6d42e7dSPeter Dunlap * has been shifted when the key/value pair(s) are being 2006a6d42e7dSPeter Dunlap * handled in the previous call iscsit_handle_security_key. 2007a6d42e7dSPeter Dunlap * Now it turns to target to check the authentication phase 2008a6d42e7dSPeter Dunlap * and shift it after taking some authentication action. 2009a6d42e7dSPeter Dunlap */ 2010a6d42e7dSPeter Dunlap kvrc = iscsit_reply_security_key(ict); 2011a6d42e7dSPeter Dunlap idm_kvstat_to_error(kvrc, &error_class, &error_detail); 2012a6d42e7dSPeter Dunlap } else if (!ict->ict_login_sm.icl_auth_pass) { 2013a6d42e7dSPeter Dunlap /* 2014a6d42e7dSPeter Dunlap * Check to see if the target allows initiators to bypass the 2015a6d42e7dSPeter Dunlap * security check. If the target is configured to require 2016a6d42e7dSPeter Dunlap * authentication, we reject the connection. 2017a6d42e7dSPeter Dunlap */ 2018a6d42e7dSPeter Dunlap if (am_list[0] == AM_NONE || am_list[0] == 0) { 2019a6d42e7dSPeter Dunlap ict->ict_login_sm.icl_auth_pass = 1; 2020a6d42e7dSPeter Dunlap } else { 2021a6d42e7dSPeter Dunlap error_class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 2022a6d42e7dSPeter Dunlap error_detail = ISCSI_LOGIN_STATUS_AUTH_FAILED; 2023a6d42e7dSPeter Dunlap } 2024a6d42e7dSPeter Dunlap } 2025a6d42e7dSPeter Dunlap 2026a6d42e7dSPeter Dunlap if (error_class == ISCSI_STATUS_CLASS_SUCCESS) { 2027a6d42e7dSPeter Dunlap idm_status = IDM_STATUS_SUCCESS; 2028a6d42e7dSPeter Dunlap } else { 2029a6d42e7dSPeter Dunlap /* supply login class/detail for login errors */ 2030a6d42e7dSPeter Dunlap SET_LOGIN_ERROR(ict, error_class, error_detail); 2031a6d42e7dSPeter Dunlap idm_status = IDM_STATUS_FAIL; 2032a6d42e7dSPeter Dunlap } 2033a6d42e7dSPeter Dunlap 2034a6d42e7dSPeter Dunlap return (idm_status); 2035a6d42e7dSPeter Dunlap } 2036a6d42e7dSPeter Dunlap 20374142b486SJames Moore static idm_pdu_t * 2038a6d42e7dSPeter Dunlap login_sm_build_login_response(iscsit_conn_t *ict) 2039a6d42e7dSPeter Dunlap { 2040a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2041a6d42e7dSPeter Dunlap iscsi_login_rsp_hdr_t *lh; 2042a6d42e7dSPeter Dunlap int transit, text_transit = 1; 20434142b486SJames Moore idm_pdu_t *login_resp; 2044a6d42e7dSPeter Dunlap 2045a6d42e7dSPeter Dunlap /* 20464142b486SJames Moore * Create a response PDU and fill it with as much of 20474142b486SJames Moore * the response text that will fit. 2048a6d42e7dSPeter Dunlap */ 2049a6d42e7dSPeter Dunlap 20504142b486SJames Moore if (lsm->icl_login_resp_itb) { 20514142b486SJames Moore /* allocate a pdu with space for text */ 20524142b486SJames Moore login_resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), 20534142b486SJames Moore ISCSI_DEFAULT_MAX_RECV_SEG_LEN); 20544142b486SJames Moore /* copy a chunk of text into the pdu */ 20554142b486SJames Moore lsm->icl_login_resp_buf = idm_pdu_init_text_data( 20564142b486SJames Moore login_resp, lsm->icl_login_resp_itb, 20574142b486SJames Moore ISCSI_DEFAULT_MAX_RECV_SEG_LEN, 20584142b486SJames Moore lsm->icl_login_resp_buf, &text_transit); 20594142b486SJames Moore if (text_transit) { 20604142b486SJames Moore /* text buf has been consumed */ 20614142b486SJames Moore idm_itextbuf_free(lsm->icl_login_resp_itb); 20624142b486SJames Moore lsm->icl_login_resp_itb = NULL; 20634142b486SJames Moore lsm->icl_login_resp_buf = NULL; 2064a6d42e7dSPeter Dunlap } 2065a6d42e7dSPeter Dunlap } else { 20664142b486SJames Moore /* allocate a pdu for just a header */ 20674142b486SJames Moore login_resp = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0); 2068a6d42e7dSPeter Dunlap } 20694142b486SJames Moore /* finish initializing the pdu */ 20704142b486SJames Moore idm_pdu_init(login_resp, 20714142b486SJames Moore ict->ict_ic, ict, login_resp_complete_cb); 20724142b486SJames Moore login_resp->isp_flags |= IDM_PDU_LOGIN_TX; 2073a6d42e7dSPeter Dunlap 2074a6d42e7dSPeter Dunlap /* 2075a6d42e7dSPeter Dunlap * Use the BHS header values from the response template 2076a6d42e7dSPeter Dunlap */ 2077a6d42e7dSPeter Dunlap bcopy(lsm->icl_login_resp_tmpl, 20784142b486SJames Moore login_resp->isp_hdr, sizeof (iscsi_login_rsp_hdr_t)); 2079a6d42e7dSPeter Dunlap 20804142b486SJames Moore lh = (iscsi_login_rsp_hdr_t *)login_resp->isp_hdr; 2081a6d42e7dSPeter Dunlap 2082a6d42e7dSPeter Dunlap /* Set error class/detail */ 2083a6d42e7dSPeter Dunlap lh->status_class = lsm->icl_login_resp_err_class; 2084a6d42e7dSPeter Dunlap lh->status_detail = lsm->icl_login_resp_err_detail; 2085a6d42e7dSPeter Dunlap /* Set CSG, NSG and Transit */ 2086a6d42e7dSPeter Dunlap lh->flags = 0; 2087a6d42e7dSPeter Dunlap lh->flags |= lsm->icl_login_csg << 2; 2088a6d42e7dSPeter Dunlap 2089a6d42e7dSPeter Dunlap 2090a6d42e7dSPeter Dunlap if (lh->status_class == ISCSI_STATUS_CLASS_SUCCESS) { 2091a6d42e7dSPeter Dunlap if (lsm->icl_login_transit && 2092a6d42e7dSPeter Dunlap lsm->icl_auth_pass != 0) { 2093a6d42e7dSPeter Dunlap transit = 1; 2094a6d42e7dSPeter Dunlap } else { 2095a6d42e7dSPeter Dunlap transit = 0; 2096a6d42e7dSPeter Dunlap } 2097a6d42e7dSPeter Dunlap /* 2098a6d42e7dSPeter Dunlap * inititalize the text data 2099a6d42e7dSPeter Dunlap */ 2100a6d42e7dSPeter Dunlap if (transit == 1 && text_transit == 1) { 2101a6d42e7dSPeter Dunlap lh->flags |= lsm->icl_login_nsg; 2102a6d42e7dSPeter Dunlap lsm->icl_login_csg = lsm->icl_login_nsg; 2103a6d42e7dSPeter Dunlap lh->flags |= ISCSI_FLAG_LOGIN_TRANSIT; 2104a6d42e7dSPeter Dunlap } else { 2105a6d42e7dSPeter Dunlap lh->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; 2106a6d42e7dSPeter Dunlap } 2107a6d42e7dSPeter Dunlap 2108a6d42e7dSPeter Dunlap /* If we are transitioning to FFP then set TSIH */ 2109a6d42e7dSPeter Dunlap if (transit && (lh->flags & ISCSI_FLAG_LOGIN_TRANSIT) && 2110a6d42e7dSPeter Dunlap lsm->icl_login_csg == ISCSI_FULL_FEATURE_PHASE) { 2111a6d42e7dSPeter Dunlap lh->tsid = htons(ict->ict_sess->ist_tsih); 2112a6d42e7dSPeter Dunlap } 2113a6d42e7dSPeter Dunlap } else { 21144142b486SJames Moore login_resp->isp_data = 0; 21154142b486SJames Moore login_resp->isp_datalen = 0; 2116a6d42e7dSPeter Dunlap } 21174142b486SJames Moore return (login_resp); 2118a6d42e7dSPeter Dunlap } 2119a6d42e7dSPeter Dunlap 2120a6d42e7dSPeter Dunlap static kv_status_t 2121a6d42e7dSPeter Dunlap iscsit_handle_key(iscsit_conn_t *ict, nvpair_t *nvp, char *nvp_name) 2122a6d42e7dSPeter Dunlap { 2123a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2124a6d42e7dSPeter Dunlap kv_status_t kvrc; 2125a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx; 2126a6d42e7dSPeter Dunlap 2127a6d42e7dSPeter Dunlap ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name)); 2128a6d42e7dSPeter Dunlap if (ikvx->ik_key_id == KI_MAX_KEY) { 2129a6d42e7dSPeter Dunlap /* 2130a6d42e7dSPeter Dunlap * Any key not understood by the acceptor may be igonred 2131a6d42e7dSPeter Dunlap * by the acceptor without affecting the basic function. 2132a6d42e7dSPeter Dunlap * However, the answer for a key not understood MUST be 2133a6d42e7dSPeter Dunlap * key=NotUnderstood. 2134a6d42e7dSPeter Dunlap */ 2135a6d42e7dSPeter Dunlap kvrc = iscsit_reply_string(ict, nvp_name, 2136a6d42e7dSPeter Dunlap ISCSI_TEXT_NOTUNDERSTOOD); 2137a6d42e7dSPeter Dunlap } else { 2138a6d42e7dSPeter Dunlap kvrc = iscsit_handle_common_key(ict, nvp, ikvx); 2139a6d42e7dSPeter Dunlap if (kvrc == KV_UNHANDLED) { 2140a6d42e7dSPeter Dunlap switch (lsm->icl_login_csg) { 2141a6d42e7dSPeter Dunlap case ISCSI_SECURITY_NEGOTIATION_STAGE: 2142a6d42e7dSPeter Dunlap kvrc = iscsit_handle_security_key( 2143a6d42e7dSPeter Dunlap ict, nvp, ikvx); 2144a6d42e7dSPeter Dunlap break; 2145a6d42e7dSPeter Dunlap case ISCSI_OP_PARMS_NEGOTIATION_STAGE: 2146a6d42e7dSPeter Dunlap kvrc = iscsit_handle_operational_key( 2147a6d42e7dSPeter Dunlap ict, nvp, ikvx); 2148a6d42e7dSPeter Dunlap break; 2149a6d42e7dSPeter Dunlap case ISCSI_FULL_FEATURE_PHASE: 2150a6d42e7dSPeter Dunlap default: 2151a6d42e7dSPeter Dunlap /* What are we doing here? */ 2152a6d42e7dSPeter Dunlap ASSERT(0); 2153a6d42e7dSPeter Dunlap kvrc = KV_UNHANDLED; 2154a6d42e7dSPeter Dunlap } 2155a6d42e7dSPeter Dunlap } 2156a6d42e7dSPeter Dunlap } 2157a6d42e7dSPeter Dunlap 2158a6d42e7dSPeter Dunlap return (kvrc); 2159a6d42e7dSPeter Dunlap } 2160a6d42e7dSPeter Dunlap 2161a6d42e7dSPeter Dunlap static kv_status_t 2162a6d42e7dSPeter Dunlap iscsit_handle_common_key(iscsit_conn_t *ict, nvpair_t *nvp, 2163a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 2164a6d42e7dSPeter Dunlap { 2165a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2166a6d42e7dSPeter Dunlap kv_status_t kvrc; 2167a6d42e7dSPeter Dunlap char *string_val; 2168a6d42e7dSPeter Dunlap int nvrc; 2169a6d42e7dSPeter Dunlap 2170a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 2171a6d42e7dSPeter Dunlap case KI_INITIATOR_NAME: 2172a6d42e7dSPeter Dunlap case KI_INITIATOR_ALIAS: 2173a6d42e7dSPeter Dunlap nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp); 2174a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2175a6d42e7dSPeter Dunlap break; 2176a6d42e7dSPeter Dunlap case KI_TARGET_NAME: 2177a6d42e7dSPeter Dunlap /* We'll validate the target during login_sm_session_bind() */ 2178a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(nvp, &string_val); 2179a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); /* We built this nvlist */ 2180a6d42e7dSPeter Dunlap 2181a6d42e7dSPeter Dunlap nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp); 2182a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2183a6d42e7dSPeter Dunlap break; 2184a6d42e7dSPeter Dunlap case KI_TARGET_ALIAS: 2185a6d42e7dSPeter Dunlap case KI_TARGET_ADDRESS: 2186a6d42e7dSPeter Dunlap case KI_TARGET_PORTAL_GROUP_TAG: 2187a6d42e7dSPeter Dunlap kvrc = KV_TARGET_ONLY; /* Only the target can declare this */ 2188a6d42e7dSPeter Dunlap break; 2189a6d42e7dSPeter Dunlap case KI_SESSION_TYPE: 2190a6d42e7dSPeter Dunlap /* 2191a6d42e7dSPeter Dunlap * If we don't receive this key on the initial login 2192a6d42e7dSPeter Dunlap * we assume this is a normal session. 2193a6d42e7dSPeter Dunlap */ 2194a6d42e7dSPeter Dunlap nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp); 2195a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2196a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(nvp, &string_val); 2197a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); /* We built this nvlist */ 2198a6d42e7dSPeter Dunlap ict->ict_op.op_discovery_session = 2199a6d42e7dSPeter Dunlap strcmp(string_val, "Discovery") == 0 ? B_TRUE : B_FALSE; 2200a6d42e7dSPeter Dunlap break; 2201a6d42e7dSPeter Dunlap default: 2202a6d42e7dSPeter Dunlap /* 2203a6d42e7dSPeter Dunlap * This is not really an error but we should 2204a6d42e7dSPeter Dunlap * leave this nvpair on the list since we 2205a6d42e7dSPeter Dunlap * didn't do anything with it. Either 2206a6d42e7dSPeter Dunlap * the security or operational phase 2207a6d42e7dSPeter Dunlap * handling functions should process it. 2208a6d42e7dSPeter Dunlap */ 2209a6d42e7dSPeter Dunlap kvrc = KV_UNHANDLED; 2210a6d42e7dSPeter Dunlap break; 2211a6d42e7dSPeter Dunlap } 2212a6d42e7dSPeter Dunlap 2213a6d42e7dSPeter Dunlap return (kvrc); 2214a6d42e7dSPeter Dunlap } 2215a6d42e7dSPeter Dunlap 2216a6d42e7dSPeter Dunlap static kv_status_t 2217a6d42e7dSPeter Dunlap iscsit_handle_security_key(iscsit_conn_t *ict, nvpair_t *nvp, 2218a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 2219a6d42e7dSPeter Dunlap { 2220a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2221a6d42e7dSPeter Dunlap iscsit_auth_client_t *client = &lsm->icl_auth_client; 2222a6d42e7dSPeter Dunlap iscsikey_id_t kv_id; 2223a6d42e7dSPeter Dunlap kv_status_t kvrc; 2224a6d42e7dSPeter Dunlap iscsit_auth_handler_t handler; 2225a6d42e7dSPeter Dunlap 2226a6d42e7dSPeter Dunlap /* 2227a6d42e7dSPeter Dunlap * After all of security keys are handled, this function will 2228a6d42e7dSPeter Dunlap * be called again to verify current authentication status 2229a6d42e7dSPeter Dunlap * and perform some actual authentication work. At this time, 2230a6d42e7dSPeter Dunlap * the nvp and ikvx will be passed in as NULLs. 2231a6d42e7dSPeter Dunlap */ 2232a6d42e7dSPeter Dunlap if (ikvx != NULL) { 2233a6d42e7dSPeter Dunlap kv_id = ikvx->ik_key_id; 2234a6d42e7dSPeter Dunlap } else { 2235a6d42e7dSPeter Dunlap kv_id = 0; 2236a6d42e7dSPeter Dunlap } 2237a6d42e7dSPeter Dunlap 2238a6d42e7dSPeter Dunlap handler = iscsit_auth_get_handler(client, kv_id); 2239a6d42e7dSPeter Dunlap if (handler) { 2240a6d42e7dSPeter Dunlap kvrc = handler(ict, nvp, ikvx); 2241a6d42e7dSPeter Dunlap } else { 2242a6d42e7dSPeter Dunlap kvrc = KV_UNHANDLED; /* invalid request */ 2243a6d42e7dSPeter Dunlap } 2244a6d42e7dSPeter Dunlap 2245a6d42e7dSPeter Dunlap return (kvrc); 2246a6d42e7dSPeter Dunlap } 2247a6d42e7dSPeter Dunlap 2248a6d42e7dSPeter Dunlap static kv_status_t 2249a6d42e7dSPeter Dunlap iscsit_reply_security_key(iscsit_conn_t *ict) 2250a6d42e7dSPeter Dunlap { 2251a6d42e7dSPeter Dunlap return (iscsit_handle_security_key(ict, NULL, NULL)); 2252a6d42e7dSPeter Dunlap } 2253a6d42e7dSPeter Dunlap 2254a6d42e7dSPeter Dunlap static kv_status_t 2255a6d42e7dSPeter Dunlap iscsit_handle_operational_key(iscsit_conn_t *ict, nvpair_t *nvp, 2256a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 2257a6d42e7dSPeter Dunlap { 2258a6d42e7dSPeter Dunlap kv_status_t kvrc = KV_UNHANDLED; 2259a6d42e7dSPeter Dunlap boolean_t bool_val; 2260a6d42e7dSPeter Dunlap uint64_t num_val; 2261a6d42e7dSPeter Dunlap int nvrc; 2262a6d42e7dSPeter Dunlap 2263a6d42e7dSPeter Dunlap /* 2264a6d42e7dSPeter Dunlap * Retrieve values. All value lookups are expected to succeed 2265a6d42e7dSPeter Dunlap * since we build the nvlist while decoding the text buffer. This 2266a6d42e7dSPeter Dunlap * step is intended to eliminate some duplication of code (for example 2267a6d42e7dSPeter Dunlap * we only need to code the numerical value lookup once). We will 2268a6d42e7dSPeter Dunlap * handle the values (if necessary) below. 2269a6d42e7dSPeter Dunlap */ 2270a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 2271a6d42e7dSPeter Dunlap /* Lists */ 2272a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 2273a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 2274a6d42e7dSPeter Dunlap break; 2275a6d42e7dSPeter Dunlap /* Booleans */ 2276a6d42e7dSPeter Dunlap case KI_INITIAL_R2T: 2277a6d42e7dSPeter Dunlap case KI_IMMEDIATE_DATA: 2278a6d42e7dSPeter Dunlap case KI_DATA_PDU_IN_ORDER: 2279a6d42e7dSPeter Dunlap case KI_DATA_SEQUENCE_IN_ORDER: 2280a6d42e7dSPeter Dunlap case KI_IFMARKER: 2281a6d42e7dSPeter Dunlap case KI_OFMARKER: 2282a6d42e7dSPeter Dunlap nvrc = nvpair_value_boolean_value(nvp, &bool_val); 2283a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); /* We built this nvlist */ 2284a6d42e7dSPeter Dunlap break; 2285a6d42e7dSPeter Dunlap /* Numericals */ 2286a6d42e7dSPeter Dunlap case KI_MAX_CONNECTIONS: 2287a6d42e7dSPeter Dunlap case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 2288a6d42e7dSPeter Dunlap case KI_MAX_BURST_LENGTH: 2289a6d42e7dSPeter Dunlap case KI_FIRST_BURST_LENGTH: 2290a6d42e7dSPeter Dunlap case KI_DEFAULT_TIME_2_WAIT: 2291a6d42e7dSPeter Dunlap case KI_DEFAULT_TIME_2_RETAIN: 2292a6d42e7dSPeter Dunlap case KI_MAX_OUTSTANDING_R2T: 2293a6d42e7dSPeter Dunlap case KI_ERROR_RECOVERY_LEVEL: 2294a6d42e7dSPeter Dunlap nvrc = nvpair_value_uint64(nvp, &num_val); 2295a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2296a6d42e7dSPeter Dunlap break; 2297a6d42e7dSPeter Dunlap /* Ranges */ 2298a6d42e7dSPeter Dunlap case KI_OFMARKERINT: 2299a6d42e7dSPeter Dunlap case KI_IFMARKERINT: 2300a6d42e7dSPeter Dunlap break; 2301a6d42e7dSPeter Dunlap default: 2302a6d42e7dSPeter Dunlap break; 2303a6d42e7dSPeter Dunlap } 2304a6d42e7dSPeter Dunlap 2305a6d42e7dSPeter Dunlap /* 2306a6d42e7dSPeter Dunlap * Now handle the values according to the key name. Sometimes we 2307a6d42e7dSPeter Dunlap * don't care what the value is -- in that case we just add the nvpair 2308a6d42e7dSPeter Dunlap * to the negotiated values list. 2309a6d42e7dSPeter Dunlap */ 2310a6d42e7dSPeter Dunlap switch (ikvx->ik_key_id) { 2311a6d42e7dSPeter Dunlap case KI_HEADER_DIGEST: 2312a6d42e7dSPeter Dunlap kvrc = iscsit_handle_digest(ict, nvp, ikvx); 2313a6d42e7dSPeter Dunlap break; 2314a6d42e7dSPeter Dunlap case KI_DATA_DIGEST: 2315a6d42e7dSPeter Dunlap kvrc = iscsit_handle_digest(ict, nvp, ikvx); 2316a6d42e7dSPeter Dunlap break; 2317a6d42e7dSPeter Dunlap case KI_INITIAL_R2T: 2318a6d42e7dSPeter Dunlap /* We *require* INITIAL_R2T=yes */ 2319a6d42e7dSPeter Dunlap kvrc = iscsit_handle_boolean(ict, nvp, bool_val, ikvx, 2320a6d42e7dSPeter Dunlap B_TRUE); 2321a6d42e7dSPeter Dunlap break; 2322a6d42e7dSPeter Dunlap case KI_IMMEDIATE_DATA: 2323a6d42e7dSPeter Dunlap kvrc = iscsit_handle_boolean(ict, nvp, bool_val, ikvx, 2324263f58aaSPriya Krishnan bool_val); 2325a6d42e7dSPeter Dunlap break; 2326a6d42e7dSPeter Dunlap case KI_DATA_PDU_IN_ORDER: 2327a6d42e7dSPeter Dunlap kvrc = iscsit_handle_boolean(ict, nvp, bool_val, ikvx, 2328a6d42e7dSPeter Dunlap B_TRUE); 2329a6d42e7dSPeter Dunlap break; 2330a6d42e7dSPeter Dunlap case KI_DATA_SEQUENCE_IN_ORDER: 2331a6d42e7dSPeter Dunlap /* We allow any value for DATA_SEQUENCE_IN_ORDER */ 2332a6d42e7dSPeter Dunlap kvrc = iscsit_handle_boolean(ict, nvp, bool_val, ikvx, 2333a6d42e7dSPeter Dunlap bool_val); 2334a6d42e7dSPeter Dunlap break; 2335a6d42e7dSPeter Dunlap case KI_OFMARKER: 2336a6d42e7dSPeter Dunlap case KI_IFMARKER: 2337a6d42e7dSPeter Dunlap /* We don't support markers */ 2338a6d42e7dSPeter Dunlap kvrc = iscsit_handle_boolean(ict, nvp, bool_val, ikvx, 2339a6d42e7dSPeter Dunlap B_FALSE); 2340a6d42e7dSPeter Dunlap break; 2341a6d42e7dSPeter Dunlap case KI_MAX_CONNECTIONS: 2342a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2343a6d42e7dSPeter Dunlap ISCSI_MIN_CONNECTIONS, 2344a6d42e7dSPeter Dunlap ISCSI_MAX_CONNECTIONS, 2345a6d42e7dSPeter Dunlap ISCSIT_MAX_CONNECTIONS); 2346a6d42e7dSPeter Dunlap break; 234756261083SCharles Ting /* this is a declartive param */ 2348a6d42e7dSPeter Dunlap case KI_MAX_RECV_DATA_SEGMENT_LENGTH: 2349a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2350a6d42e7dSPeter Dunlap ISCSI_MIN_RECV_DATA_SEGMENT_LENGTH, 2351a6d42e7dSPeter Dunlap ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH, 235256261083SCharles Ting ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 2353a6d42e7dSPeter Dunlap break; 2354a6d42e7dSPeter Dunlap case KI_MAX_BURST_LENGTH: 2355a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2356a6d42e7dSPeter Dunlap ISCSI_MIN_MAX_BURST_LENGTH, 2357a6d42e7dSPeter Dunlap ISCSI_MAX_BURST_LENGTH, 2358a6d42e7dSPeter Dunlap ISCSIT_MAX_BURST_LENGTH); 2359a6d42e7dSPeter Dunlap break; 2360a6d42e7dSPeter Dunlap case KI_FIRST_BURST_LENGTH: 2361a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2362a6d42e7dSPeter Dunlap ISCSI_MIN_FIRST_BURST_LENGTH, 2363a6d42e7dSPeter Dunlap ISCSI_MAX_FIRST_BURST_LENGTH, 2364a6d42e7dSPeter Dunlap ISCSIT_MAX_FIRST_BURST_LENGTH); 2365a6d42e7dSPeter Dunlap break; 2366a6d42e7dSPeter Dunlap case KI_DEFAULT_TIME_2_WAIT: 2367a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2368a6d42e7dSPeter Dunlap ISCSI_MIN_TIME2WAIT, 2369a6d42e7dSPeter Dunlap ISCSI_MAX_TIME2WAIT, 2370a6d42e7dSPeter Dunlap ISCSIT_MAX_TIME2WAIT); 2371a6d42e7dSPeter Dunlap break; 2372a6d42e7dSPeter Dunlap case KI_DEFAULT_TIME_2_RETAIN: 2373a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2374a6d42e7dSPeter Dunlap ISCSI_MIN_TIME2RETAIN, 2375a6d42e7dSPeter Dunlap ISCSI_MAX_TIME2RETAIN, 2376a6d42e7dSPeter Dunlap ISCSIT_MAX_TIME2RETAIN); 2377a6d42e7dSPeter Dunlap break; 2378a6d42e7dSPeter Dunlap case KI_MAX_OUTSTANDING_R2T: 2379a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2380a6d42e7dSPeter Dunlap ISCSI_MIN_MAX_OUTSTANDING_R2T, 2381a6d42e7dSPeter Dunlap ISCSI_MAX_OUTSTANDING_R2T, 2382a6d42e7dSPeter Dunlap ISCSIT_MAX_OUTSTANDING_R2T); 2383a6d42e7dSPeter Dunlap break; 2384a6d42e7dSPeter Dunlap case KI_ERROR_RECOVERY_LEVEL: 2385a6d42e7dSPeter Dunlap kvrc = iscsit_handle_numerical(ict, nvp, num_val, ikvx, 2386a6d42e7dSPeter Dunlap ISCSI_MIN_ERROR_RECOVERY_LEVEL, 2387a6d42e7dSPeter Dunlap ISCSI_MAX_ERROR_RECOVERY_LEVEL, 2388a6d42e7dSPeter Dunlap ISCSIT_MAX_ERROR_RECOVERY_LEVEL); 2389a6d42e7dSPeter Dunlap break; 2390a6d42e7dSPeter Dunlap case KI_OFMARKERINT: 2391a6d42e7dSPeter Dunlap case KI_IFMARKERINT: 2392a6d42e7dSPeter Dunlap kvrc = iscsit_reply_string(ict, ikvx->ik_key_name, 2393a6d42e7dSPeter Dunlap ISCSI_TEXT_IRRELEVANT); 2394a6d42e7dSPeter Dunlap break; 2395a6d42e7dSPeter Dunlap default: 2396a6d42e7dSPeter Dunlap kvrc = KV_UNHANDLED; /* invalid request */ 2397a6d42e7dSPeter Dunlap break; 2398a6d42e7dSPeter Dunlap } 2399a6d42e7dSPeter Dunlap 2400a6d42e7dSPeter Dunlap return (kvrc); 2401a6d42e7dSPeter Dunlap } 2402a6d42e7dSPeter Dunlap 2403a6d42e7dSPeter Dunlap static kv_status_t 2404a6d42e7dSPeter Dunlap iscsit_reply_numerical(iscsit_conn_t *ict, 2405a6d42e7dSPeter Dunlap const char *nvp_name, const uint64_t value) 2406a6d42e7dSPeter Dunlap { 2407a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2408a6d42e7dSPeter Dunlap kv_status_t kvrc; 2409a6d42e7dSPeter Dunlap int nvrc; 2410a6d42e7dSPeter Dunlap 2411a6d42e7dSPeter Dunlap nvrc = nvlist_add_uint64(lsm->icl_response_nvlist, 2412a6d42e7dSPeter Dunlap nvp_name, value); 2413a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2414a6d42e7dSPeter Dunlap 2415a6d42e7dSPeter Dunlap return (kvrc); 2416a6d42e7dSPeter Dunlap } 2417a6d42e7dSPeter Dunlap 2418a6d42e7dSPeter Dunlap static kv_status_t 2419a6d42e7dSPeter Dunlap iscsit_reply_string(iscsit_conn_t *ict, 2420a6d42e7dSPeter Dunlap const char *nvp_name, const char *text) 2421a6d42e7dSPeter Dunlap { 2422a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2423a6d42e7dSPeter Dunlap kv_status_t kvrc; 2424a6d42e7dSPeter Dunlap int nvrc; 2425a6d42e7dSPeter Dunlap 2426a6d42e7dSPeter Dunlap nvrc = nvlist_add_string(lsm->icl_response_nvlist, 2427a6d42e7dSPeter Dunlap nvp_name, text); 2428a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2429a6d42e7dSPeter Dunlap 2430a6d42e7dSPeter Dunlap return (kvrc); 2431a6d42e7dSPeter Dunlap } 2432a6d42e7dSPeter Dunlap 2433a6d42e7dSPeter Dunlap static kv_status_t 2434a6d42e7dSPeter Dunlap iscsit_handle_digest(iscsit_conn_t *ict, nvpair_t *choices, 2435a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx) 2436a6d42e7dSPeter Dunlap { 2437a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2438a6d42e7dSPeter Dunlap kv_status_t kvrc = KV_VALUE_ERROR; 2439a6d42e7dSPeter Dunlap int nvrc; 2440a6d42e7dSPeter Dunlap nvpair_t *digest_choice; 2441a6d42e7dSPeter Dunlap char *digest_choice_string; 2442a6d42e7dSPeter Dunlap 2443a6d42e7dSPeter Dunlap /* 2444a6d42e7dSPeter Dunlap * Need to add persistent config here if we want users to allow 2445a6d42e7dSPeter Dunlap * disabling of digests on the target side. You could argue that 2446a6d42e7dSPeter Dunlap * this makes things too complicated... just let the initiator state 2447a6d42e7dSPeter Dunlap * what it wants and we'll take it. For now that's exactly what 2448a6d42e7dSPeter Dunlap * we'll do. 2449a6d42e7dSPeter Dunlap * 2450a6d42e7dSPeter Dunlap * Basic digest negotiation happens here at iSCSI level. IDM 2451a6d42e7dSPeter Dunlap * can override this during negotiate_key_values phase to 2452a6d42e7dSPeter Dunlap * decline to set up any digest processing. 2453a6d42e7dSPeter Dunlap */ 2454a6d42e7dSPeter Dunlap digest_choice = idm_get_next_listvalue(choices, NULL); 2455a6d42e7dSPeter Dunlap 2456a6d42e7dSPeter Dunlap /* 2457a6d42e7dSPeter Dunlap * Loop through all choices. As soon as we find a choice 2458a6d42e7dSPeter Dunlap * that we support add the value to our negotiated values list 2459a6d42e7dSPeter Dunlap * and respond with that value in the login response. 2460a6d42e7dSPeter Dunlap */ 2461a6d42e7dSPeter Dunlap while (digest_choice != NULL) { 2462a6d42e7dSPeter Dunlap nvrc = nvpair_value_string(digest_choice, 2463a6d42e7dSPeter Dunlap &digest_choice_string); 2464a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2465a6d42e7dSPeter Dunlap 2466a6d42e7dSPeter Dunlap if ((strcasecmp(digest_choice_string, "crc32c") == 0) || 2467a6d42e7dSPeter Dunlap (strcasecmp(digest_choice_string, "none") == 0)) { 2468a6d42e7dSPeter Dunlap /* Add to negotiated values list */ 2469a6d42e7dSPeter Dunlap nvrc = nvlist_add_string(lsm->icl_negotiated_values, 2470a6d42e7dSPeter Dunlap ikvx->ik_key_name, digest_choice_string); 2471a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2472a6d42e7dSPeter Dunlap if (nvrc == 0) { 2473a6d42e7dSPeter Dunlap /* Add to login response list */ 2474a6d42e7dSPeter Dunlap nvrc = nvlist_add_string( 2475a6d42e7dSPeter Dunlap lsm->icl_response_nvlist, 2476a6d42e7dSPeter Dunlap ikvx->ik_key_name, digest_choice_string); 2477a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2478a6d42e7dSPeter Dunlap } 2479a6d42e7dSPeter Dunlap break; 2480a6d42e7dSPeter Dunlap } 2481a6d42e7dSPeter Dunlap digest_choice = idm_get_next_listvalue(choices, 2482a6d42e7dSPeter Dunlap digest_choice); 2483a6d42e7dSPeter Dunlap } 2484a6d42e7dSPeter Dunlap 2485a6d42e7dSPeter Dunlap if (digest_choice == NULL) 2486a6d42e7dSPeter Dunlap kvrc = KV_VALUE_ERROR; 2487a6d42e7dSPeter Dunlap 2488a6d42e7dSPeter Dunlap return (kvrc); 2489a6d42e7dSPeter Dunlap } 2490a6d42e7dSPeter Dunlap 2491a6d42e7dSPeter Dunlap static kv_status_t 2492a6d42e7dSPeter Dunlap iscsit_handle_boolean(iscsit_conn_t *ict, nvpair_t *nvp, boolean_t value, 2493a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx, boolean_t iscsit_value) 2494a6d42e7dSPeter Dunlap { 2495a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2496a6d42e7dSPeter Dunlap kv_status_t kvrc; 2497a6d42e7dSPeter Dunlap int nvrc; 2498a6d42e7dSPeter Dunlap 249956261083SCharles Ting if (ikvx->ik_declarative) { 250056261083SCharles Ting nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp); 2501a6d42e7dSPeter Dunlap } else { 250256261083SCharles Ting if (value != iscsit_value) { 250356261083SCharles Ting /* Respond back to initiator with our value */ 250456261083SCharles Ting value = iscsit_value; 2505c050a449SPeter Gill nvrc = nvlist_add_boolean_value( 2506c050a449SPeter Gill lsm->icl_negotiated_values, 2507c050a449SPeter Gill ikvx->ik_key_name, value); 250856261083SCharles Ting lsm->icl_login_transit = B_FALSE; 250956261083SCharles Ting } else { 251056261083SCharles Ting /* Add this to our negotiated values */ 251156261083SCharles Ting nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, 251256261083SCharles Ting nvp); 251356261083SCharles Ting } 2514a6d42e7dSPeter Dunlap 251556261083SCharles Ting /* Response of Simple-value Negotiation */ 251656261083SCharles Ting if (nvrc == 0) { 251756261083SCharles Ting nvrc = nvlist_add_boolean_value( 251856261083SCharles Ting lsm->icl_response_nvlist, ikvx->ik_key_name, value); 251956261083SCharles Ting } 2520a6d42e7dSPeter Dunlap } 252156261083SCharles Ting 2522a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2523a6d42e7dSPeter Dunlap 2524a6d42e7dSPeter Dunlap return (kvrc); 2525a6d42e7dSPeter Dunlap } 2526a6d42e7dSPeter Dunlap 2527a6d42e7dSPeter Dunlap static kv_status_t 2528a6d42e7dSPeter Dunlap iscsit_handle_numerical(iscsit_conn_t *ict, nvpair_t *nvp, uint64_t value, 2529a6d42e7dSPeter Dunlap const idm_kv_xlate_t *ikvx, 2530a6d42e7dSPeter Dunlap uint64_t iscsi_min_value, uint64_t iscsi_max_value, 2531a6d42e7dSPeter Dunlap uint64_t iscsit_max_value) 2532a6d42e7dSPeter Dunlap { 2533a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2534a6d42e7dSPeter Dunlap kv_status_t kvrc; 2535a6d42e7dSPeter Dunlap int nvrc; 2536a6d42e7dSPeter Dunlap 2537a6d42e7dSPeter Dunlap /* Validate against standard */ 2538a6d42e7dSPeter Dunlap if ((value < iscsi_min_value) || (value > iscsi_max_value)) { 2539a6d42e7dSPeter Dunlap kvrc = KV_VALUE_ERROR; 254056261083SCharles Ting } else if (ikvx->ik_declarative) { 254156261083SCharles Ting nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, nvp); 254256261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 2543a6d42e7dSPeter Dunlap } else { 2544a6d42e7dSPeter Dunlap if (value > iscsit_max_value) { 2545a6d42e7dSPeter Dunlap /* Respond back to initiator with our value */ 2546a6d42e7dSPeter Dunlap value = iscsit_max_value; 2547c050a449SPeter Gill nvrc = nvlist_add_uint64(lsm->icl_negotiated_values, 2548c050a449SPeter Gill ikvx->ik_key_name, value); 2549a6d42e7dSPeter Dunlap lsm->icl_login_transit = B_FALSE; 2550a6d42e7dSPeter Dunlap } else { 2551a6d42e7dSPeter Dunlap /* Add this to our negotiated values */ 2552a6d42e7dSPeter Dunlap nvrc = nvlist_add_nvpair(lsm->icl_negotiated_values, 2553a6d42e7dSPeter Dunlap nvp); 2554a6d42e7dSPeter Dunlap } 2555a6d42e7dSPeter Dunlap 2556a6d42e7dSPeter Dunlap /* Response of Simple-value Negotiation */ 255756261083SCharles Ting if (nvrc == 0) { 2558a6d42e7dSPeter Dunlap nvrc = nvlist_add_uint64(lsm->icl_response_nvlist, 2559a6d42e7dSPeter Dunlap ikvx->ik_key_name, value); 2560a6d42e7dSPeter Dunlap } 2561a6d42e7dSPeter Dunlap kvrc = idm_nvstat_to_kvstat(nvrc); 2562a6d42e7dSPeter Dunlap } 2563a6d42e7dSPeter Dunlap 2564a6d42e7dSPeter Dunlap return (kvrc); 2565a6d42e7dSPeter Dunlap } 2566a6d42e7dSPeter Dunlap 2567a6d42e7dSPeter Dunlap 2568a6d42e7dSPeter Dunlap static void 2569a6d42e7dSPeter Dunlap iscsit_process_negotiated_values(iscsit_conn_t *ict) 2570a6d42e7dSPeter Dunlap { 2571a6d42e7dSPeter Dunlap iscsit_conn_login_t *lsm = &ict->ict_login_sm; 2572a6d42e7dSPeter Dunlap char *string_val; 2573a6d42e7dSPeter Dunlap boolean_t boolean_val; 2574a6d42e7dSPeter Dunlap uint64_t uint64_val; 2575a6d42e7dSPeter Dunlap int nvrc; 2576a6d42e7dSPeter Dunlap 2577a6d42e7dSPeter Dunlap /* Let the IDM level activate its parameters first */ 257830e7468fSPeter Dunlap idm_notice_key_values(ict->ict_ic, lsm->icl_negotiated_values); 2579a6d42e7dSPeter Dunlap 2580a6d42e7dSPeter Dunlap /* 2581a6d42e7dSPeter Dunlap * Initiator alias and target alias 2582a6d42e7dSPeter Dunlap */ 2583a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_string(lsm->icl_negotiated_values, 2584a6d42e7dSPeter Dunlap "InitiatorAlias", &string_val)) != ENOENT) { 2585a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2586a6d42e7dSPeter Dunlap ict->ict_sess->ist_initiator_alias = 2587a6d42e7dSPeter Dunlap kmem_alloc(strlen(string_val) + 1, KM_SLEEP); 2588a6d42e7dSPeter Dunlap (void) strcpy(ict->ict_sess->ist_initiator_alias, string_val); 2589ca3b8945SYuri Pankov if (ict->ict_sess->ist_stmf_sess) 2590ca3b8945SYuri Pankov ict->ict_sess->ist_stmf_sess->ss_rport_alias = 2591ca3b8945SYuri Pankov strdup(string_val); 2592a6d42e7dSPeter Dunlap } 2593a6d42e7dSPeter Dunlap 2594a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_string(lsm->icl_negotiated_values, 2595a6d42e7dSPeter Dunlap "TargetAlias", &string_val)) != ENOENT) { 2596a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2597a6d42e7dSPeter Dunlap ict->ict_sess->ist_target_alias = 2598a6d42e7dSPeter Dunlap kmem_alloc(strlen(string_val) + 1, KM_SLEEP); 2599a6d42e7dSPeter Dunlap (void) strcpy(ict->ict_sess->ist_target_alias, string_val); 2600a6d42e7dSPeter Dunlap } 2601a6d42e7dSPeter Dunlap 2602a6d42e7dSPeter Dunlap /* 2603a6d42e7dSPeter Dunlap * Operational parameters. We process SessionType when it is 2604a6d42e7dSPeter Dunlap * initially received since it is required on the initial login. 2605a6d42e7dSPeter Dunlap */ 2606a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_boolean_value(lsm->icl_negotiated_values, 2607a6d42e7dSPeter Dunlap "InitialR2T", &boolean_val)) != ENOENT) { 2608a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2609a6d42e7dSPeter Dunlap ict->ict_op.op_initial_r2t = boolean_val; 2610a6d42e7dSPeter Dunlap } 2611a6d42e7dSPeter Dunlap 2612a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_boolean_value(lsm->icl_negotiated_values, 2613a6d42e7dSPeter Dunlap "ImmediateData", &boolean_val)) != ENOENT) { 2614a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2615a6d42e7dSPeter Dunlap ict->ict_op.op_immed_data = boolean_val; 2616a6d42e7dSPeter Dunlap } 2617a6d42e7dSPeter Dunlap 2618a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_boolean_value(lsm->icl_negotiated_values, 2619a6d42e7dSPeter Dunlap "DataPDUInOrder", &boolean_val)) != ENOENT) { 2620a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2621a6d42e7dSPeter Dunlap ict->ict_op.op_data_pdu_in_order = boolean_val; 2622a6d42e7dSPeter Dunlap } 2623a6d42e7dSPeter Dunlap 2624a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_boolean_value(lsm->icl_negotiated_values, 2625a6d42e7dSPeter Dunlap "DataSequenceInOrder", &boolean_val)) != ENOENT) { 2626a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2627a6d42e7dSPeter Dunlap ict->ict_op.op_data_sequence_in_order = boolean_val; 2628a6d42e7dSPeter Dunlap } 2629a6d42e7dSPeter Dunlap 2630a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2631a6d42e7dSPeter Dunlap "MaxConnections", &uint64_val)) != ENOENT) { 2632a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2633a6d42e7dSPeter Dunlap ict->ict_op.op_max_connections = uint64_val; 2634a6d42e7dSPeter Dunlap } 2635a6d42e7dSPeter Dunlap 2636a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2637a6d42e7dSPeter Dunlap "MaxRecvDataSegmentLength", &uint64_val)) != ENOENT) { 2638a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2639a6d42e7dSPeter Dunlap ict->ict_op.op_max_recv_data_segment_length = uint64_val; 2640a6d42e7dSPeter Dunlap } 2641a6d42e7dSPeter Dunlap 2642a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2643a6d42e7dSPeter Dunlap "MaxBurstLength", &uint64_val)) != ENOENT) { 2644a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2645a6d42e7dSPeter Dunlap ict->ict_op.op_max_burst_length = uint64_val; 2646a6d42e7dSPeter Dunlap } 2647a6d42e7dSPeter Dunlap 2648a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2649a6d42e7dSPeter Dunlap "FirstBurstLength", &uint64_val)) != ENOENT) { 2650a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2651a6d42e7dSPeter Dunlap ict->ict_op.op_first_burst_length = uint64_val; 2652a6d42e7dSPeter Dunlap } 2653a6d42e7dSPeter Dunlap 2654a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2655a6d42e7dSPeter Dunlap "DefaultTime2Wait", &uint64_val)) != ENOENT) { 2656a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2657a6d42e7dSPeter Dunlap ict->ict_op.op_default_time_2_wait = uint64_val; 2658a6d42e7dSPeter Dunlap } 2659a6d42e7dSPeter Dunlap 2660a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2661a6d42e7dSPeter Dunlap "DefaultTime2Retain", &uint64_val)) != ENOENT) { 2662a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2663a6d42e7dSPeter Dunlap ict->ict_op.op_default_time_2_retain = uint64_val; 2664a6d42e7dSPeter Dunlap } 2665a6d42e7dSPeter Dunlap 2666a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2667a6d42e7dSPeter Dunlap "MaxOutstandingR2T", &uint64_val)) != ENOENT) { 2668a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2669a6d42e7dSPeter Dunlap ict->ict_op.op_max_outstanding_r2t = uint64_val; 2670a6d42e7dSPeter Dunlap } 2671a6d42e7dSPeter Dunlap 2672a6d42e7dSPeter Dunlap if ((nvrc = nvlist_lookup_uint64(lsm->icl_negotiated_values, 2673a6d42e7dSPeter Dunlap "ErrorRecoveryLevel", &uint64_val)) != ENOENT) { 2674a6d42e7dSPeter Dunlap ASSERT(nvrc == 0); 2675a6d42e7dSPeter Dunlap ict->ict_op.op_error_recovery_level = uint64_val; 2676a6d42e7dSPeter Dunlap } 2677a6d42e7dSPeter Dunlap } 267856261083SCharles Ting 267956261083SCharles Ting static idm_status_t 268056261083SCharles Ting iscsit_add_declarative_keys(iscsit_conn_t *ict) 268156261083SCharles Ting { 268256261083SCharles Ting nvlist_t *cfg_nv = NULL; 268356261083SCharles Ting kv_status_t kvrc; 268456261083SCharles Ting int nvrc; 268556261083SCharles Ting iscsit_conn_login_t *lsm = &ict->ict_login_sm; 268656261083SCharles Ting uint8_t error_class; 268756261083SCharles Ting uint8_t error_detail; 268856261083SCharles Ting idm_status_t idm_status; 268956261083SCharles Ting 269056261083SCharles Ting if ((nvrc = nvlist_alloc(&cfg_nv, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) { 269156261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 269256261083SCharles Ting goto alloc_fail; 269356261083SCharles Ting } 269456261083SCharles Ting if ((nvrc = nvlist_add_uint64(cfg_nv, "MaxRecvDataSegmentLength", 269556261083SCharles Ting max_dataseglen_target)) != 0) { 269656261083SCharles Ting kvrc = idm_nvstat_to_kvstat(nvrc); 269756261083SCharles Ting goto done; 269856261083SCharles Ting } 269956261083SCharles Ting 270056261083SCharles Ting kvrc = idm_declare_key_values(ict->ict_ic, cfg_nv, 270156261083SCharles Ting lsm->icl_response_nvlist); 270256261083SCharles Ting done: 270356261083SCharles Ting nvlist_free(cfg_nv); 270456261083SCharles Ting alloc_fail: 270556261083SCharles Ting idm_kvstat_to_error(kvrc, &error_class, &error_detail); 270656261083SCharles Ting if (error_class == ISCSI_STATUS_CLASS_SUCCESS) { 270756261083SCharles Ting idm_status = IDM_STATUS_SUCCESS; 270856261083SCharles Ting } else { 270956261083SCharles Ting SET_LOGIN_ERROR(ict, error_class, error_detail); 271056261083SCharles Ting idm_status = IDM_STATUS_FAIL; 271156261083SCharles Ting } 271256261083SCharles Ting return (idm_status); 271356261083SCharles Ting } 27141ef61828SYuri Pankov 27151ef61828SYuri Pankov static char * 27161ef61828SYuri Pankov iscsit_fold_name(char *name, size_t *buflen) 27171ef61828SYuri Pankov { 27181ef61828SYuri Pankov char *ret; 27191ef61828SYuri Pankov const char *sns; 27201ef61828SYuri Pankov int errnum; 27211ef61828SYuri Pankov int flag = U8_TEXTPREP_NFKC; 27221ef61828SYuri Pankov size_t inlen, outlen, coff; 27231ef61828SYuri Pankov 27241ef61828SYuri Pankov if (name == NULL) 27251ef61828SYuri Pankov return (NULL); 27261ef61828SYuri Pankov 27271ef61828SYuri Pankov /* Check for one of the supported name types */ 27281ef61828SYuri Pankov if (strncasecmp(name, SNS_EUI ".", strlen(SNS_EUI) + 1) == 0) { 27291ef61828SYuri Pankov sns = SNS_EUI; 27301ef61828SYuri Pankov *buflen = SNS_EUI_U8_LEN_MAX + 1; 27311ef61828SYuri Pankov flag |= U8_TEXTPREP_TOUPPER; 27321ef61828SYuri Pankov } else if (strncasecmp(name, SNS_IQN ".", strlen(SNS_IQN) + 1) == 0) { 27331ef61828SYuri Pankov sns = SNS_IQN; 27341ef61828SYuri Pankov *buflen = SNS_IQN_U8_LEN_MAX + 1; 27351ef61828SYuri Pankov flag |= U8_TEXTPREP_TOLOWER; 27361ef61828SYuri Pankov } else if (strncasecmp(name, SNS_NAA ".", strlen(SNS_NAA) + 1) == 0) { 27371ef61828SYuri Pankov sns = SNS_NAA; 27381ef61828SYuri Pankov *buflen = SNS_NAA_U8_LEN_MAX + 1; 27391ef61828SYuri Pankov flag |= U8_TEXTPREP_TOUPPER; 27401ef61828SYuri Pankov } else { 27411ef61828SYuri Pankov return (NULL); 27421ef61828SYuri Pankov } 27431ef61828SYuri Pankov 27441ef61828SYuri Pankov ret = kmem_zalloc(*buflen, KM_SLEEP); 27451ef61828SYuri Pankov coff = strlen(sns); 27461ef61828SYuri Pankov inlen = strlen(name) - coff; 27471ef61828SYuri Pankov outlen = *buflen - coff; 27481ef61828SYuri Pankov 27491ef61828SYuri Pankov /* Fold the case and normalize string */ 27501ef61828SYuri Pankov if (u8_textprep_str(name + coff, &inlen, ret + coff, &outlen, flag, 27511ef61828SYuri Pankov U8_UNICODE_320, &errnum) == (size_t)-1) { 27521ef61828SYuri Pankov kmem_free(ret, *buflen); 27531ef61828SYuri Pankov return (NULL); 27541ef61828SYuri Pankov } 27551ef61828SYuri Pankov 27561ef61828SYuri Pankov /* Copy the name type prefix */ 27571ef61828SYuri Pankov bcopy(sns, ret, coff); 27581ef61828SYuri Pankov 27591ef61828SYuri Pankov return (ret); 27601ef61828SYuri Pankov } 2761