1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte * CDDL HEADER START
3fcf3ce44SJohn Forte *
4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte *
8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte * and limitations under the License.
12fcf3ce44SJohn Forte *
13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte *
19fcf3ce44SJohn Forte * CDDL HEADER END
20fcf3ce44SJohn Forte */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte * Copyright 2000 by Cisco Systems, Inc. All rights reserved.
23904e51f6SJack Meng * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24fcf3ce44SJohn Forte *
25fcf3ce44SJohn Forte * iSCSI protocol login and enumeration
26fcf3ce44SJohn Forte */
27fcf3ce44SJohn Forte
28fcf3ce44SJohn Forte #include "iscsi.h"
291a1a84a3SPeter Dunlap #include <sys/iscsi_protocol.h>
30fcf3ce44SJohn Forte #include <sys/scsi/adapters/iscsi_door.h>
31fcf3ce44SJohn Forte
3230e7468fSPeter Dunlap boolean_t iscsi_login_logging = B_FALSE;
3330e7468fSPeter Dunlap
34fcf3ce44SJohn Forte /* internal login protocol interfaces */
35fcf3ce44SJohn Forte static iscsi_status_t iscsi_login(iscsi_conn_t *icp,
3630e7468fSPeter Dunlap uint8_t *status_class, uint8_t *status_detail);
3730e7468fSPeter Dunlap static int iscsi_add_text(idm_pdu_t *text_pdu,
38fcf3ce44SJohn Forte int max_data_length, char *param, char *value);
39fcf3ce44SJohn Forte static int iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
40fcf3ce44SJohn Forte char **value_start, char **value_end);
41fcf3ce44SJohn Forte static void iscsi_null_callback(void *user_handle, void *message_handle,
42fcf3ce44SJohn Forte int auth_status);
43fcf3ce44SJohn Forte static iscsi_status_t iscsi_process_login_response(iscsi_conn_t *icp,
44fcf3ce44SJohn Forte iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length);
45fcf3ce44SJohn Forte static iscsi_status_t iscsi_make_login_pdu(iscsi_conn_t *icp,
4630e7468fSPeter Dunlap idm_pdu_t *text_pdu, char *data, int max_data_length);
47fcf3ce44SJohn Forte static iscsi_status_t iscsi_update_address(iscsi_conn_t *icp,
48fcf3ce44SJohn Forte char *address);
49fcf3ce44SJohn Forte static char *iscsi_login_failure_str(uchar_t status_class,
50fcf3ce44SJohn Forte uchar_t status_detail);
51fcf3ce44SJohn Forte static void iscsi_login_end(iscsi_conn_t *icp,
5230e7468fSPeter Dunlap iscsi_status_t status, iscsi_task_t *itp);
53fcf3ce44SJohn Forte static iscsi_status_t iscsi_login_connect(iscsi_conn_t *icp);
5430e7468fSPeter Dunlap static void iscsi_login_disconnect(iscsi_conn_t *icp);
5530e7468fSPeter Dunlap static void iscsi_notice_key_values(iscsi_conn_t *icp);
56fcf3ce44SJohn Forte
57fcf3ce44SJohn Forte #define ISCSI_LOGIN_RETRY_DELAY 5 /* seconds */
58fcf3ce44SJohn Forte
5919944f88Syi zhang - Sun Microsystems - Beijing China #define ISCSI_LOGIN_TRANSIT_FFP(flags) \
6019944f88Syi zhang - Sun Microsystems - Beijing China (!(flags & ISCSI_FLAG_LOGIN_CONTINUE) && \
6119944f88Syi zhang - Sun Microsystems - Beijing China (flags & ISCSI_FLAG_LOGIN_TRANSIT) && \
6219944f88Syi zhang - Sun Microsystems - Beijing China (ISCSI_LOGIN_CURRENT_STAGE(flags) == \
6319944f88Syi zhang - Sun Microsystems - Beijing China ISCSI_OP_PARMS_NEGOTIATION_STAGE) && \
6419944f88Syi zhang - Sun Microsystems - Beijing China (ISCSI_LOGIN_NEXT_STAGE(flags) == \
6519944f88Syi zhang - Sun Microsystems - Beijing China ISCSI_FULL_FEATURE_PHASE))
6619944f88Syi zhang - Sun Microsystems - Beijing China
67fcf3ce44SJohn Forte /*
68fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
69fcf3ce44SJohn Forte * | External Login Interface |
70fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
71fcf3ce44SJohn Forte */
72fcf3ce44SJohn Forte
73*9fe633fdSToomas Soome void
iscsi_login_cb(void * arg)74*9fe633fdSToomas Soome iscsi_login_cb(void *arg)
75*9fe633fdSToomas Soome {
76*9fe633fdSToomas Soome (void) iscsi_login_start(arg);
77*9fe633fdSToomas Soome }
78*9fe633fdSToomas Soome
79fcf3ce44SJohn Forte /*
80fcf3ce44SJohn Forte * iscsi_login_start - connect and perform iscsi protocol login
81fcf3ce44SJohn Forte */
82fcf3ce44SJohn Forte iscsi_status_t
iscsi_login_start(void * arg)83fcf3ce44SJohn Forte iscsi_login_start(void *arg)
84fcf3ce44SJohn Forte {
85fcf3ce44SJohn Forte iscsi_task_t *itp = (iscsi_task_t *)arg;
86fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_LOGIN_FAILED;
87fcf3ce44SJohn Forte iscsi_conn_t *icp;
88fcf3ce44SJohn Forte iscsi_sess_t *isp;
89fcf3ce44SJohn Forte iscsi_hba_t *ihp;
90fcf3ce44SJohn Forte unsigned char status_class;
91fcf3ce44SJohn Forte unsigned char status_detail;
92fcf3ce44SJohn Forte
93fcf3ce44SJohn Forte ASSERT(itp != NULL);
94fcf3ce44SJohn Forte icp = (iscsi_conn_t *)itp->t_arg;
95fcf3ce44SJohn Forte ASSERT(icp != NULL);
96fcf3ce44SJohn Forte isp = icp->conn_sess;
97fcf3ce44SJohn Forte ASSERT(isp != NULL);
98fcf3ce44SJohn Forte ihp = isp->sess_hba;
99fcf3ce44SJohn Forte ASSERT(ihp != NULL);
100fcf3ce44SJohn Forte
101fcf3ce44SJohn Forte login_start:
10230e7468fSPeter Dunlap ASSERT((icp->conn_state == ISCSI_CONN_STATE_IN_LOGIN) ||
10330e7468fSPeter Dunlap (icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
10430e7468fSPeter Dunlap (icp->conn_state == ISCSI_CONN_STATE_POLLING));
10530e7468fSPeter Dunlap
10630e7468fSPeter Dunlap icp->conn_state_ffp = B_FALSE;
107cc7ef495Syi zhang - Sun Microsystems - Beijing China icp->conn_login_status = ISCSI_INITIAL_LOGIN_STAGE;
10830e7468fSPeter Dunlap
109fcf3ce44SJohn Forte /* reset connection statsn */
110fcf3ce44SJohn Forte icp->conn_expstatsn = 0;
111fcf3ce44SJohn Forte icp->conn_laststatsn = 0;
112fcf3ce44SJohn Forte
113fcf3ce44SJohn Forte /* sync up authentication information */
114fcf3ce44SJohn Forte (void) iscsi_sess_set_auth(isp);
115fcf3ce44SJohn Forte
116fcf3ce44SJohn Forte /* sync up login and session parameters */
117fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_conn_sync_params(icp))) {
118fcf3ce44SJohn Forte /* unable to sync params. fail connection attempts */
11930e7468fSPeter Dunlap iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
120fcf3ce44SJohn Forte return (ISCSI_STATUS_LOGIN_FAILED);
121fcf3ce44SJohn Forte }
122fcf3ce44SJohn Forte
12330e7468fSPeter Dunlap /*
12430e7468fSPeter Dunlap * Attempt to open TCP connection, associated IDM connection will
12530e7468fSPeter Dunlap * have a hold on it that must be released after the call to
12630e7468fSPeter Dunlap * iscsi_login() below.
12730e7468fSPeter Dunlap */
128fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_login_connect(icp))) {
129bbe72583SJack Meng if ((isp->sess_boot == B_TRUE) &&
130bbe72583SJack Meng (ihp->hba_service_status_overwrite == B_TRUE) &&
131bbe72583SJack Meng (isp->sess_boot_nic_reset == B_FALSE)) {
132bbe72583SJack Meng /*
133bbe72583SJack Meng * The connection to boot target failed
134bbe72583SJack Meng * before the system fully started.
135bbe72583SJack Meng * Reset the boot nic to the settings from
136bbe72583SJack Meng * firmware before retrying the connect to
137bbe72583SJack Meng * save the the system.
138bbe72583SJack Meng */
139bbe72583SJack Meng if (iscsi_net_interface(B_TRUE) ==
140bbe72583SJack Meng ISCSI_STATUS_SUCCESS) {
141bbe72583SJack Meng isp->sess_boot_nic_reset = B_TRUE;
142bbe72583SJack Meng }
143bbe72583SJack Meng }
144fcf3ce44SJohn Forte /* retry this failure */
145fcf3ce44SJohn Forte goto login_retry;
146fcf3ce44SJohn Forte }
147fcf3ce44SJohn Forte
148fcf3ce44SJohn Forte /*
149fcf3ce44SJohn Forte * allocate response buffer with based on default max
150fcf3ce44SJohn Forte * transfer size. This size might shift during login.
151fcf3ce44SJohn Forte */
15230e7468fSPeter Dunlap icp->conn_login_max_data_length =
15330e7468fSPeter Dunlap icp->conn_params.max_xmit_data_seg_len;
15430e7468fSPeter Dunlap icp->conn_login_data = kmem_zalloc(icp->conn_login_max_data_length,
15530e7468fSPeter Dunlap KM_SLEEP);
156fcf3ce44SJohn Forte
15730e7468fSPeter Dunlap /*
15830e7468fSPeter Dunlap * Start protocol login, upon return we will be either logged in
15930e7468fSPeter Dunlap * or disconnected
16030e7468fSPeter Dunlap */
16130e7468fSPeter Dunlap rval = iscsi_login(icp, &status_class, &status_detail);
162fcf3ce44SJohn Forte
163fcf3ce44SJohn Forte /* done with buffer */
16430e7468fSPeter Dunlap kmem_free(icp->conn_login_data, icp->conn_login_max_data_length);
16530e7468fSPeter Dunlap
16630e7468fSPeter Dunlap /* Release connection hold */
16730e7468fSPeter Dunlap idm_conn_rele(icp->conn_ic);
168fcf3ce44SJohn Forte
169fcf3ce44SJohn Forte /* hard failure in login */
170fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(rval)) {
171fcf3ce44SJohn Forte /*
172fcf3ce44SJohn Forte * We should just give up retry if these failures are
173fcf3ce44SJohn Forte * detected.
174fcf3ce44SJohn Forte */
175fcf3ce44SJohn Forte switch (rval) {
176fcf3ce44SJohn Forte /*
177fcf3ce44SJohn Forte * We should just give up retry if these
178fcf3ce44SJohn Forte * failures are detected.
179fcf3ce44SJohn Forte */
180fcf3ce44SJohn Forte case ISCSI_STATUS_AUTHENTICATION_FAILED:
181fcf3ce44SJohn Forte case ISCSI_STATUS_INTERNAL_ERROR:
182fcf3ce44SJohn Forte case ISCSI_STATUS_VERSION_MISMATCH:
183fcf3ce44SJohn Forte case ISCSI_STATUS_NEGO_FAIL:
184cc7ef495Syi zhang - Sun Microsystems - Beijing China case ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL:
185fcf3ce44SJohn Forte /* we don't want to retry this failure */
18630e7468fSPeter Dunlap iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
187fcf3ce44SJohn Forte return (ISCSI_STATUS_LOGIN_FAILED);
188fcf3ce44SJohn Forte default:
189fcf3ce44SJohn Forte /* retry this failure */
190fcf3ce44SJohn Forte goto login_retry;
191fcf3ce44SJohn Forte }
192fcf3ce44SJohn Forte }
193fcf3ce44SJohn Forte
194fcf3ce44SJohn Forte /* soft failure with reason */
195fcf3ce44SJohn Forte switch (status_class) {
196fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_SUCCESS:
197fcf3ce44SJohn Forte /* login was successful */
19830e7468fSPeter Dunlap iscsi_login_end(icp, ISCSI_STATUS_SUCCESS, itp);
199fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
200fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_REDIRECT:
201fcf3ce44SJohn Forte /* Retry at the redirected address */
202fcf3ce44SJohn Forte goto login_start;
203fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_TARGET_ERR:
204fcf3ce44SJohn Forte /* retry this failure */
205fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
206fcf3ce44SJohn Forte "%s (0x%02x/0x%02x)", icp->conn_oid,
207fcf3ce44SJohn Forte iscsi_login_failure_str(status_class, status_detail),
208fcf3ce44SJohn Forte status_class, status_detail);
209fcf3ce44SJohn Forte goto login_retry;
210fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_INITIATOR_ERR:
211fcf3ce44SJohn Forte default:
212fcf3ce44SJohn Forte /* All other errors are hard failures */
213fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
2147f848965Sbing zhao - Sun Microsystems - Beijing China "%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
2157f848965Sbing zhao - Sun Microsystems - Beijing China icp->conn_oid,
216fcf3ce44SJohn Forte iscsi_login_failure_str(status_class, status_detail),
2177f848965Sbing zhao - Sun Microsystems - Beijing China status_class, status_detail, isp->sess_name,
2187f848965Sbing zhao - Sun Microsystems - Beijing China isp->sess_tpgt_conf);
219fcf3ce44SJohn Forte
220fcf3ce44SJohn Forte /* we don't want to retry this failure */
22130e7468fSPeter Dunlap iscsi_login_end(icp, ISCSI_STATUS_LOGIN_FAILED, itp);
222fcf3ce44SJohn Forte break;
223fcf3ce44SJohn Forte }
22430e7468fSPeter Dunlap
225fcf3ce44SJohn Forte return (ISCSI_STATUS_LOGIN_FAILED);
226fcf3ce44SJohn Forte
227fcf3ce44SJohn Forte login_retry:
228fcf3ce44SJohn Forte /* retry this failure if we haven't run out of time */
229fcf3ce44SJohn Forte if (icp->conn_login_max > ddi_get_lbolt()) {
230fcf3ce44SJohn Forte
231fcf3ce44SJohn Forte if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
232fcf3ce44SJohn Forte icp->conn_login_min = ddi_get_lbolt() +
233aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(icp->conn_tunable_params.
234aff4bce5Syi zhang - Sun Microsystems - Beijing China polling_login_delay);
235fcf3ce44SJohn Forte } else {
236fcf3ce44SJohn Forte icp->conn_login_min = ddi_get_lbolt() +
237fcf3ce44SJohn Forte SEC_TO_TICK(ISCSI_LOGIN_RETRY_DELAY);
238fcf3ce44SJohn Forte }
239fcf3ce44SJohn Forte
240fcf3ce44SJohn Forte if (itp->t_blocking == B_TRUE) {
241fcf3ce44SJohn Forte goto login_start;
242fcf3ce44SJohn Forte } else {
243904e51f6SJack Meng if (ddi_taskq_dispatch(isp->sess_login_taskq,
244*9fe633fdSToomas Soome iscsi_login_cb, itp, DDI_SLEEP) !=
245fcf3ce44SJohn Forte DDI_SUCCESS) {
246fcf3ce44SJohn Forte iscsi_login_end(icp,
24730e7468fSPeter Dunlap ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
248fcf3ce44SJohn Forte }
249fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
250fcf3ce44SJohn Forte }
251fcf3ce44SJohn Forte } else {
252fcf3ce44SJohn Forte /* Retries exceeded */
25330e7468fSPeter Dunlap iscsi_login_end(icp, ISCSI_STATUS_LOGIN_TIMED_OUT, itp);
254fcf3ce44SJohn Forte }
25530e7468fSPeter Dunlap
256fcf3ce44SJohn Forte return (ISCSI_STATUS_LOGIN_FAILED);
257fcf3ce44SJohn Forte }
258fcf3ce44SJohn Forte
259fcf3ce44SJohn Forte static void
iscsi_login_end(iscsi_conn_t * icp,iscsi_status_t status,iscsi_task_t * itp)26030e7468fSPeter Dunlap iscsi_login_end(iscsi_conn_t *icp, iscsi_status_t status, iscsi_task_t *itp)
261fcf3ce44SJohn Forte {
262fcf3ce44SJohn Forte iscsi_sess_t *isp;
263904e51f6SJack Meng uint32_t event_count;
264fcf3ce44SJohn Forte
265fcf3ce44SJohn Forte ASSERT(icp != NULL);
266fcf3ce44SJohn Forte isp = icp->conn_sess;
267fcf3ce44SJohn Forte ASSERT(isp != NULL);
268fcf3ce44SJohn Forte
26930e7468fSPeter Dunlap if (status == ISCSI_STATUS_SUCCESS) {
27030e7468fSPeter Dunlap /* Inform IDM of the relevant negotiated values */
27130e7468fSPeter Dunlap iscsi_notice_key_values(icp);
27230e7468fSPeter Dunlap
27330e7468fSPeter Dunlap /* We are now logged in */
27430e7468fSPeter Dunlap iscsi_conn_update_state(icp, ISCSI_CONN_STATE_LOGGED_IN);
27530e7468fSPeter Dunlap
27630e7468fSPeter Dunlap /* startup TX thread */
27730e7468fSPeter Dunlap (void) iscsi_thread_start(icp->conn_tx_thread);
27830e7468fSPeter Dunlap
27930e7468fSPeter Dunlap /*
28030e7468fSPeter Dunlap * Move login state machine to LOGIN_FFP. This will
28130e7468fSPeter Dunlap * release the taskq thread handling the CN_FFP_ENABLED
28230e7468fSPeter Dunlap * allowing the IDM connection state machine to resume
28330e7468fSPeter Dunlap * processing events
28430e7468fSPeter Dunlap */
28530e7468fSPeter Dunlap iscsi_login_update_state(icp, LOGIN_FFP);
28630e7468fSPeter Dunlap
28730e7468fSPeter Dunlap /* Notify the session that a connection is logged in */
288904e51f6SJack Meng event_count = atomic_inc_32_nv(&isp->sess_state_event_count);
289904e51f6SJack Meng iscsi_sess_enter_state_zone(isp);
290904e51f6SJack Meng iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N1, event_count);
291904e51f6SJack Meng iscsi_sess_exit_state_zone(isp);
29230e7468fSPeter Dunlap } else {
29330e7468fSPeter Dunlap /* If login failed reset nego tpgt */
29430e7468fSPeter Dunlap isp->sess_tpgt_nego = ISCSI_DEFAULT_TPGT;
29530e7468fSPeter Dunlap
296fcf3ce44SJohn Forte mutex_enter(&icp->conn_state_mutex);
29730e7468fSPeter Dunlap switch (icp->conn_state) {
29830e7468fSPeter Dunlap case ISCSI_CONN_STATE_IN_LOGIN:
29930e7468fSPeter Dunlap iscsi_conn_update_state_locked(icp,
30030e7468fSPeter Dunlap ISCSI_CONN_STATE_FREE);
30130e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
30230e7468fSPeter Dunlap break;
30330e7468fSPeter Dunlap case ISCSI_CONN_STATE_FAILED:
30430e7468fSPeter Dunlap if (status == ISCSI_STATUS_LOGIN_FAILED) {
30530e7468fSPeter Dunlap iscsi_conn_update_state_locked(icp,
30630e7468fSPeter Dunlap ISCSI_CONN_STATE_FREE);
30730e7468fSPeter Dunlap } else {
30830e7468fSPeter Dunlap /* ISCSI_STATUS_LOGIN_TIMED_OUT */
30930e7468fSPeter Dunlap iscsi_conn_update_state_locked(icp,
31030e7468fSPeter Dunlap ISCSI_CONN_STATE_POLLING);
31130e7468fSPeter Dunlap }
312fcf3ce44SJohn Forte mutex_exit(&icp->conn_state_mutex);
313904e51f6SJack Meng event_count = atomic_inc_32_nv(
314904e51f6SJack Meng &isp->sess_state_event_count);
315904e51f6SJack Meng iscsi_sess_enter_state_zone(isp);
316904e51f6SJack Meng iscsi_sess_state_machine(isp, ISCSI_SESS_EVENT_N6,
317904e51f6SJack Meng event_count);
318904e51f6SJack Meng iscsi_sess_exit_state_zone(isp);
31930e7468fSPeter Dunlap
32030e7468fSPeter Dunlap if (status == ISCSI_STATUS_LOGIN_TIMED_OUT) {
32130e7468fSPeter Dunlap iscsi_conn_retry(isp, icp);
32230e7468fSPeter Dunlap }
32330e7468fSPeter Dunlap break;
32430e7468fSPeter Dunlap case ISCSI_CONN_STATE_POLLING:
32530e7468fSPeter Dunlap if (status == ISCSI_STATUS_LOGIN_FAILED) {
32630e7468fSPeter Dunlap iscsi_conn_update_state_locked(icp,
32730e7468fSPeter Dunlap ISCSI_CONN_STATE_FREE);
32830e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
329904e51f6SJack Meng event_count = atomic_inc_32_nv(
330904e51f6SJack Meng &isp->sess_state_event_count);
331904e51f6SJack Meng iscsi_sess_enter_state_zone(isp);
33230e7468fSPeter Dunlap
33330e7468fSPeter Dunlap iscsi_sess_state_machine(isp,
334904e51f6SJack Meng ISCSI_SESS_EVENT_N6, event_count);
335904e51f6SJack Meng
336904e51f6SJack Meng iscsi_sess_exit_state_zone(isp);
33730e7468fSPeter Dunlap } else {
33830e7468fSPeter Dunlap /* ISCSI_STATUS_LOGIN_TIMED_OUT */
33930e7468fSPeter Dunlap if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
34030e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
34130e7468fSPeter Dunlap
34230e7468fSPeter Dunlap iscsi_conn_retry(isp, icp);
34330e7468fSPeter Dunlap } else {
34430e7468fSPeter Dunlap iscsi_conn_update_state_locked(icp,
34530e7468fSPeter Dunlap ISCSI_CONN_STATE_FREE);
34630e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
34730e7468fSPeter Dunlap }
34830e7468fSPeter Dunlap }
34930e7468fSPeter Dunlap break;
35019944f88Syi zhang - Sun Microsystems - Beijing China case ISCSI_CONN_STATE_FREE:
35119944f88Syi zhang - Sun Microsystems - Beijing China mutex_exit(&icp->conn_state_mutex);
35219944f88Syi zhang - Sun Microsystems - Beijing China break;
35330e7468fSPeter Dunlap default:
35419944f88Syi zhang - Sun Microsystems - Beijing China mutex_exit(&icp->conn_state_mutex);
35530e7468fSPeter Dunlap ASSERT(0);
35630e7468fSPeter Dunlap break;
35730e7468fSPeter Dunlap }
358fcf3ce44SJohn Forte }
359fcf3ce44SJohn Forte
360fcf3ce44SJohn Forte if (itp->t_blocking == B_FALSE) {
361fcf3ce44SJohn Forte kmem_free(itp, sizeof (iscsi_task_t));
362fcf3ce44SJohn Forte }
363bbe72583SJack Meng
364bbe72583SJack Meng isp->sess_boot_nic_reset = B_FALSE;
365fcf3ce44SJohn Forte }
366fcf3ce44SJohn Forte
367fcf3ce44SJohn Forte /*
368fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
369fcf3ce44SJohn Forte * | Begin of protocol login routines |
370fcf3ce44SJohn Forte * +--------------------------------------------------------------------+
371fcf3ce44SJohn Forte */
372fcf3ce44SJohn Forte
373fcf3ce44SJohn Forte /*
374fcf3ce44SJohn Forte * iscsi_login - Attempt to login to the target. The caller
375fcf3ce44SJohn Forte * must check the status class to determine if the login succeeded.
376fcf3ce44SJohn Forte * A return of 1 does not mean the login succeeded, it just means
377fcf3ce44SJohn Forte * this function worked, and the status class is valid info. This
378fcf3ce44SJohn Forte * allows the caller to decide whether or not to retry logins, so
379fcf3ce44SJohn Forte * that we don't have any policy logic here.
380fcf3ce44SJohn Forte */
38130e7468fSPeter Dunlap iscsi_status_t
iscsi_login(iscsi_conn_t * icp,uint8_t * status_class,uint8_t * status_detail)38230e7468fSPeter Dunlap iscsi_login(iscsi_conn_t *icp, uint8_t *status_class, uint8_t *status_detail)
383fcf3ce44SJohn Forte {
384fcf3ce44SJohn Forte iscsi_status_t rval = ISCSI_STATUS_INTERNAL_ERROR;
385fcf3ce44SJohn Forte struct iscsi_sess *isp = NULL;
386fcf3ce44SJohn Forte IscsiAuthClient *auth_client = NULL;
387fcf3ce44SJohn Forte int max_data_length = 0;
388fcf3ce44SJohn Forte char *data = NULL;
38930e7468fSPeter Dunlap idm_pdu_t *text_pdu;
39030e7468fSPeter Dunlap char *buffer;
39130e7468fSPeter Dunlap size_t bufsize;
39230e7468fSPeter Dunlap iscsi_login_rsp_hdr_t *ilrhp;
39330e7468fSPeter Dunlap clock_t response_timeout, timeout_result;
39430e7468fSPeter Dunlap
39530e7468fSPeter Dunlap buffer = icp->conn_login_data;
39630e7468fSPeter Dunlap bufsize = icp->conn_login_max_data_length;
397fcf3ce44SJohn Forte
398fcf3ce44SJohn Forte ASSERT(icp != NULL);
399fcf3ce44SJohn Forte ASSERT(buffer != NULL);
400fcf3ce44SJohn Forte ASSERT(status_class != NULL);
401fcf3ce44SJohn Forte ASSERT(status_detail != NULL);
402fcf3ce44SJohn Forte isp = icp->conn_sess;
403fcf3ce44SJohn Forte ASSERT(isp != NULL);
404fcf3ce44SJohn Forte
405fcf3ce44SJohn Forte /*
40630e7468fSPeter Dunlap * prepare the connection, hold IDM connection until login completes
407fcf3ce44SJohn Forte */
408fcf3ce44SJohn Forte icp->conn_current_stage = ISCSI_INITIAL_LOGIN_STAGE;
409fcf3ce44SJohn Forte icp->conn_partial_response = 0;
410fcf3ce44SJohn Forte
411fcf3ce44SJohn Forte if (isp->sess_auth.auth_buffers &&
412fcf3ce44SJohn Forte isp->sess_auth.num_auth_buffers) {
413fcf3ce44SJohn Forte
414fcf3ce44SJohn Forte auth_client = (IscsiAuthClient *)isp->
415fcf3ce44SJohn Forte sess_auth.auth_buffers[0].address;
416fcf3ce44SJohn Forte
417fcf3ce44SJohn Forte /*
418fcf3ce44SJohn Forte * prepare for authentication
419fcf3ce44SJohn Forte */
420fcf3ce44SJohn Forte if (iscsiAuthClientInit(iscsiAuthNodeTypeInitiator,
421fcf3ce44SJohn Forte isp->sess_auth.num_auth_buffers,
422fcf3ce44SJohn Forte isp->sess_auth.auth_buffers) !=
423fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
424fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
425fcf3ce44SJohn Forte "unable to initialize authentication",
426fcf3ce44SJohn Forte icp->conn_oid);
427cc7ef495Syi zhang - Sun Microsystems - Beijing China icp->conn_login_status = ISCSI_STATUS_INTERNAL_ERROR;
42830e7468fSPeter Dunlap iscsi_login_disconnect(icp);
42930e7468fSPeter Dunlap iscsi_login_update_state(icp, LOGIN_DONE);
430fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
431fcf3ce44SJohn Forte }
432fcf3ce44SJohn Forte
433fcf3ce44SJohn Forte if (iscsiAuthClientSetVersion(auth_client,
434fcf3ce44SJohn Forte iscsiAuthVersionRfc) != iscsiAuthStatusNoError) {
435fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
436fcf3ce44SJohn Forte "unable to set authentication", icp->conn_oid);
437fcf3ce44SJohn Forte goto iscsi_login_done;
438fcf3ce44SJohn Forte }
439fcf3ce44SJohn Forte
440fcf3ce44SJohn Forte if (isp->sess_auth.username &&
441fcf3ce44SJohn Forte (iscsiAuthClientSetUsername(auth_client,
442fcf3ce44SJohn Forte isp->sess_auth.username) !=
443fcf3ce44SJohn Forte iscsiAuthStatusNoError)) {
444fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
445fcf3ce44SJohn Forte "unable to set username", icp->conn_oid);
446fcf3ce44SJohn Forte goto iscsi_login_done;
447fcf3ce44SJohn Forte }
448fcf3ce44SJohn Forte
449fcf3ce44SJohn Forte if (isp->sess_auth.password &&
450fcf3ce44SJohn Forte (iscsiAuthClientSetPassword(auth_client,
451fcf3ce44SJohn Forte isp->sess_auth.password, isp->sess_auth.password_length) !=
452fcf3ce44SJohn Forte iscsiAuthStatusNoError)) {
453fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
454fcf3ce44SJohn Forte "unable to set password", icp->conn_oid);
455fcf3ce44SJohn Forte goto iscsi_login_done;
456fcf3ce44SJohn Forte }
457fcf3ce44SJohn Forte
458fcf3ce44SJohn Forte if (iscsiAuthClientSetIpSec(auth_client, 1) !=
459fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
460fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
461fcf3ce44SJohn Forte "unable to set ipsec", icp->conn_oid);
462fcf3ce44SJohn Forte goto iscsi_login_done;
463fcf3ce44SJohn Forte }
464fcf3ce44SJohn Forte
465fcf3ce44SJohn Forte if (iscsiAuthClientSetAuthRemote(auth_client,
466fcf3ce44SJohn Forte isp->sess_auth.bidirectional_auth) !=
467fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
468fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
469fcf3ce44SJohn Forte "unable to set remote authentication",
470fcf3ce44SJohn Forte icp->conn_oid);
471fcf3ce44SJohn Forte goto iscsi_login_done;
472fcf3ce44SJohn Forte }
473fcf3ce44SJohn Forte }
474fcf3ce44SJohn Forte
475fcf3ce44SJohn Forte /*
476fcf3ce44SJohn Forte * exchange PDUs until the login stage is complete, or an error occurs
477fcf3ce44SJohn Forte */
478fcf3ce44SJohn Forte do {
479fcf3ce44SJohn Forte /* setup */
480fcf3ce44SJohn Forte bzero(buffer, bufsize);
481fcf3ce44SJohn Forte data = buffer;
482fcf3ce44SJohn Forte max_data_length = bufsize;
483fcf3ce44SJohn Forte rval = ISCSI_STATUS_INTERNAL_ERROR;
484fcf3ce44SJohn Forte
48530e7468fSPeter Dunlap text_pdu = idm_pdu_alloc(sizeof (iscsi_hdr_t), 0);
48630e7468fSPeter Dunlap idm_pdu_init(text_pdu, icp->conn_ic, NULL, NULL);
48730e7468fSPeter Dunlap
488fcf3ce44SJohn Forte /*
489fcf3ce44SJohn Forte * fill in the PDU header and text data based on the
490fcf3ce44SJohn Forte * login stage that we're in
491fcf3ce44SJohn Forte */
49230e7468fSPeter Dunlap rval = iscsi_make_login_pdu(icp, text_pdu, data,
49330e7468fSPeter Dunlap max_data_length);
494fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(rval)) {
495fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
496fcf3ce44SJohn Forte "unable to make login pdu", icp->conn_oid);
497fcf3ce44SJohn Forte goto iscsi_login_done;
498fcf3ce44SJohn Forte }
499fcf3ce44SJohn Forte
50030e7468fSPeter Dunlap mutex_enter(&icp->conn_login_mutex);
50130e7468fSPeter Dunlap /*
50230e7468fSPeter Dunlap * Make sure we are still in LOGIN_START or LOGIN_RX
50330e7468fSPeter Dunlap * state before switching to LOGIN_TX. It's possible
50430e7468fSPeter Dunlap * for a connection failure to move us to LOGIN_ERROR
50530e7468fSPeter Dunlap * before we get to this point.
50630e7468fSPeter Dunlap */
50730e7468fSPeter Dunlap if (((icp->conn_login_state != LOGIN_READY) &&
50830e7468fSPeter Dunlap (icp->conn_login_state != LOGIN_RX)) ||
50930e7468fSPeter Dunlap !icp->conn_state_idm_connected) {
51030e7468fSPeter Dunlap /* Error occurred */
51130e7468fSPeter Dunlap mutex_exit(&icp->conn_login_mutex);
51230e7468fSPeter Dunlap rval = (ISCSI_STATUS_INTERNAL_ERROR);
513fcf3ce44SJohn Forte goto iscsi_login_done;
514fcf3ce44SJohn Forte }
515fcf3ce44SJohn Forte
5166e7514aeSPeter Gill icp->conn_login_resp_hdr.opcode = 0;
51730e7468fSPeter Dunlap iscsi_login_update_state_locked(icp, LOGIN_TX);
51830e7468fSPeter Dunlap icp->conn_login_data = data;
51930e7468fSPeter Dunlap icp->conn_login_max_data_length = max_data_length;
520fcf3ce44SJohn Forte
52130e7468fSPeter Dunlap /*
52230e7468fSPeter Dunlap * send a PDU to the target. This is asynchronous but
52330e7468fSPeter Dunlap * we don't have any particular need for a TX completion
52430e7468fSPeter Dunlap * notification since we are going to block waiting for the
52530e7468fSPeter Dunlap * receive.
52630e7468fSPeter Dunlap */
52730e7468fSPeter Dunlap response_timeout = ddi_get_lbolt() +
528aff4bce5Syi zhang - Sun Microsystems - Beijing China SEC_TO_TICK(icp->conn_tunable_params.
529aff4bce5Syi zhang - Sun Microsystems - Beijing China recv_login_rsp_timeout);
53030e7468fSPeter Dunlap idm_pdu_tx(text_pdu);
53130e7468fSPeter Dunlap
53230e7468fSPeter Dunlap /*
53330e7468fSPeter Dunlap * Wait for login failure indication or login RX.
53430e7468fSPeter Dunlap * Handler for login response PDU will copy any data into
53530e7468fSPeter Dunlap * the buffer pointed to by icp->conn_login_data
53630e7468fSPeter Dunlap */
53730e7468fSPeter Dunlap while (icp->conn_login_state == LOGIN_TX) {
53830e7468fSPeter Dunlap timeout_result = cv_timedwait(&icp->conn_login_cv,
53930e7468fSPeter Dunlap &icp->conn_login_mutex, response_timeout);
54030e7468fSPeter Dunlap if (timeout_result == -1)
54130e7468fSPeter Dunlap break;
54230e7468fSPeter Dunlap }
54330e7468fSPeter Dunlap
5446e7514aeSPeter Gill /*
5456e7514aeSPeter Gill * We have either received a login response or the connection
5466e7514aeSPeter Gill * has gone down or both. If a login response is present,
5476e7514aeSPeter Gill * then process it.
5486e7514aeSPeter Gill */
5496e7514aeSPeter Gill ilrhp = (iscsi_login_rsp_hdr_t *)&icp->conn_login_resp_hdr;
5506e7514aeSPeter Gill if (icp->conn_login_state != LOGIN_RX && ilrhp->opcode == 0) {
5516e7514aeSPeter Gill /* connection down, with no login response */
55230e7468fSPeter Dunlap mutex_exit(&icp->conn_login_mutex);
55330e7468fSPeter Dunlap rval = (ISCSI_STATUS_INTERNAL_ERROR);
554fcf3ce44SJohn Forte goto iscsi_login_done;
555fcf3ce44SJohn Forte }
55630e7468fSPeter Dunlap mutex_exit(&icp->conn_login_mutex);
557fcf3ce44SJohn Forte
558fcf3ce44SJohn Forte /* check the PDU response type */
55930e7468fSPeter Dunlap if (ilrhp->opcode != ISCSI_OP_LOGIN_RSP) {
560fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
561fcf3ce44SJohn Forte "received invalid login response (0x%02x)",
56230e7468fSPeter Dunlap icp->conn_oid, ilrhp->opcode);
563fcf3ce44SJohn Forte rval = (ISCSI_STATUS_PROTOCOL_ERROR);
564fcf3ce44SJohn Forte goto iscsi_login_done;
565fcf3ce44SJohn Forte }
566fcf3ce44SJohn Forte
567fcf3ce44SJohn Forte /*
568fcf3ce44SJohn Forte * give the caller the status class and detail from the
569fcf3ce44SJohn Forte * last login response PDU received
570fcf3ce44SJohn Forte */
571fcf3ce44SJohn Forte if (status_class) {
572fcf3ce44SJohn Forte *status_class = ilrhp->status_class;
573fcf3ce44SJohn Forte }
574fcf3ce44SJohn Forte if (status_detail) {
575fcf3ce44SJohn Forte *status_detail = ilrhp->status_detail;
576fcf3ce44SJohn Forte }
577fcf3ce44SJohn Forte
578fcf3ce44SJohn Forte switch (ilrhp->status_class) {
579fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_SUCCESS:
580fcf3ce44SJohn Forte /*
581fcf3ce44SJohn Forte * process this response and possibly continue
582fcf3ce44SJohn Forte * sending PDUs
583fcf3ce44SJohn Forte */
584fcf3ce44SJohn Forte rval = iscsi_process_login_response(icp,
58530e7468fSPeter Dunlap ilrhp, (char *)icp->conn_login_data,
58630e7468fSPeter Dunlap icp->conn_login_max_data_length);
587fcf3ce44SJohn Forte /* pass back whatever error we discovered */
588fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(rval)) {
58919944f88Syi zhang - Sun Microsystems - Beijing China if (ISCSI_LOGIN_TRANSIT_FFP(ilrhp->flags)) {
59019944f88Syi zhang - Sun Microsystems - Beijing China /*
59119944f88Syi zhang - Sun Microsystems - Beijing China * iSCSI connection transit to next
59219944f88Syi zhang - Sun Microsystems - Beijing China * FFP stage while iscsi params
59319944f88Syi zhang - Sun Microsystems - Beijing China * ngeotiate error, LOGIN_ERROR
59419944f88Syi zhang - Sun Microsystems - Beijing China * marked so CN_FFP_ENABLED can
59519944f88Syi zhang - Sun Microsystems - Beijing China * be fully handled before
59619944f88Syi zhang - Sun Microsystems - Beijing China * CN_FFP_DISABLED can be processed.
59719944f88Syi zhang - Sun Microsystems - Beijing China */
59819944f88Syi zhang - Sun Microsystems - Beijing China iscsi_login_update_state(icp,
59919944f88Syi zhang - Sun Microsystems - Beijing China LOGIN_ERROR);
60019944f88Syi zhang - Sun Microsystems - Beijing China }
601fcf3ce44SJohn Forte goto iscsi_login_done;
602fcf3ce44SJohn Forte }
603fcf3ce44SJohn Forte
604fcf3ce44SJohn Forte break;
605fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_REDIRECT:
606fcf3ce44SJohn Forte /*
607fcf3ce44SJohn Forte * we need to process this response to get the
608fcf3ce44SJohn Forte * TargetAddress of the redirect, but we don't
609fcf3ce44SJohn Forte * care about the return code.
610fcf3ce44SJohn Forte */
61130e7468fSPeter Dunlap (void) iscsi_process_login_response(icp,
61230e7468fSPeter Dunlap ilrhp, (char *)icp->conn_login_data,
61330e7468fSPeter Dunlap icp->conn_login_max_data_length);
614fcf3ce44SJohn Forte rval = ISCSI_STATUS_SUCCESS;
615fcf3ce44SJohn Forte goto iscsi_login_done;
616fcf3ce44SJohn Forte case ISCSI_STATUS_CLASS_INITIATOR_ERR:
617fcf3ce44SJohn Forte if (ilrhp->status_detail ==
618fcf3ce44SJohn Forte ISCSI_LOGIN_STATUS_AUTH_FAILED) {
619fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
620fcf3ce44SJohn Forte "failed - login failed to authenticate "
621fcf3ce44SJohn Forte "with target", icp->conn_oid);
622fcf3ce44SJohn Forte }
623fcf3ce44SJohn Forte rval = ISCSI_STATUS_SUCCESS;
624fcf3ce44SJohn Forte goto iscsi_login_done;
625fcf3ce44SJohn Forte default:
626fcf3ce44SJohn Forte /*
627fcf3ce44SJohn Forte * some sort of error, login terminated unsuccessfully,
628fcf3ce44SJohn Forte * though this function did it's job. the caller must
629fcf3ce44SJohn Forte * check the status_class and status_detail and decide
630fcf3ce44SJohn Forte * what to do next.
631fcf3ce44SJohn Forte */
632fcf3ce44SJohn Forte rval = ISCSI_STATUS_SUCCESS;
633fcf3ce44SJohn Forte goto iscsi_login_done;
634fcf3ce44SJohn Forte }
635fcf3ce44SJohn Forte
636fcf3ce44SJohn Forte } while (icp->conn_current_stage != ISCSI_FULL_FEATURE_PHASE);
637fcf3ce44SJohn Forte
638fcf3ce44SJohn Forte rval = ISCSI_STATUS_SUCCESS;
639fcf3ce44SJohn Forte
640fcf3ce44SJohn Forte iscsi_login_done:
641fcf3ce44SJohn Forte if (auth_client) {
642fcf3ce44SJohn Forte if (iscsiAuthClientFinish(auth_client) !=
643fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
644fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
645fcf3ce44SJohn Forte "failed - login failed to authenticate "
646fcf3ce44SJohn Forte "with target", icp->conn_oid);
647fcf3ce44SJohn Forte if (ISCSI_SUCCESS(rval))
648fcf3ce44SJohn Forte rval = ISCSI_STATUS_INTERNAL_ERROR;
649fcf3ce44SJohn Forte }
650fcf3ce44SJohn Forte }
65130e7468fSPeter Dunlap
652cc7ef495Syi zhang - Sun Microsystems - Beijing China icp->conn_login_status = rval;
65330e7468fSPeter Dunlap if (ISCSI_SUCCESS(rval) &&
65430e7468fSPeter Dunlap (*status_class == ISCSI_STATUS_CLASS_SUCCESS)) {
65530e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex);
65630e7468fSPeter Dunlap while (!icp->conn_state_ffp)
65730e7468fSPeter Dunlap cv_wait(&icp->conn_state_change,
65830e7468fSPeter Dunlap &icp->conn_state_mutex);
65930e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
66030e7468fSPeter Dunlap } else {
66130e7468fSPeter Dunlap iscsi_login_disconnect(icp);
66230e7468fSPeter Dunlap }
66330e7468fSPeter Dunlap
66430e7468fSPeter Dunlap iscsi_login_update_state(icp, LOGIN_DONE);
66530e7468fSPeter Dunlap
666fcf3ce44SJohn Forte return (rval);
667fcf3ce44SJohn Forte }
668fcf3ce44SJohn Forte
669fcf3ce44SJohn Forte
670fcf3ce44SJohn Forte /*
671fcf3ce44SJohn Forte * iscsi_make_login_pdu -
672fcf3ce44SJohn Forte *
673fcf3ce44SJohn Forte */
674fcf3ce44SJohn Forte static iscsi_status_t
iscsi_make_login_pdu(iscsi_conn_t * icp,idm_pdu_t * text_pdu,char * data,int max_data_length)67530e7468fSPeter Dunlap iscsi_make_login_pdu(iscsi_conn_t *icp, idm_pdu_t *text_pdu,
676fcf3ce44SJohn Forte char *data, int max_data_length)
677fcf3ce44SJohn Forte {
678fcf3ce44SJohn Forte struct iscsi_sess *isp = NULL;
679fcf3ce44SJohn Forte int transit = 0;
68030e7468fSPeter Dunlap iscsi_hdr_t *ihp = text_pdu->isp_hdr;
68130e7468fSPeter Dunlap iscsi_login_hdr_t *ilhp =
68230e7468fSPeter Dunlap (iscsi_login_hdr_t *)text_pdu->isp_hdr;
683fcf3ce44SJohn Forte IscsiAuthClient *auth_client = NULL;
684fcf3ce44SJohn Forte int keytype = 0;
685fcf3ce44SJohn Forte int rc = 0;
686fcf3ce44SJohn Forte char value[iscsiAuthStringMaxLength];
687fcf3ce44SJohn Forte
688fcf3ce44SJohn Forte ASSERT(icp != NULL);
68930e7468fSPeter Dunlap ASSERT(text_pdu != NULL);
690fcf3ce44SJohn Forte isp = icp->conn_sess;
691fcf3ce44SJohn Forte ASSERT(isp != NULL);
692fcf3ce44SJohn Forte
693fcf3ce44SJohn Forte auth_client =
694fcf3ce44SJohn Forte (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
695fcf3ce44SJohn Forte (IscsiAuthClient *)isp->sess_auth.auth_buffers[0].address : NULL;
696fcf3ce44SJohn Forte
697fcf3ce44SJohn Forte /*
698fcf3ce44SJohn Forte * initialize the PDU header
699fcf3ce44SJohn Forte */
700fcf3ce44SJohn Forte bzero(ilhp, sizeof (*ilhp));
701fcf3ce44SJohn Forte ilhp->opcode = ISCSI_OP_LOGIN_CMD | ISCSI_OP_IMMEDIATE;
702fcf3ce44SJohn Forte ilhp->cid = icp->conn_cid;
703fcf3ce44SJohn Forte bcopy(&isp->sess_isid[0], &ilhp->isid[0], sizeof (isp->sess_isid));
704fcf3ce44SJohn Forte ilhp->tsid = 0;
705fcf3ce44SJohn Forte
70630e7468fSPeter Dunlap /*
70730e7468fSPeter Dunlap * Set data buffer pointer. The calls to iscsi_add_text will update the
70830e7468fSPeter Dunlap * data length.
70930e7468fSPeter Dunlap */
71030e7468fSPeter Dunlap text_pdu->isp_data = (uint8_t *)data;
71130e7468fSPeter Dunlap
712fcf3ce44SJohn Forte /* don't increment on immediate */
713fcf3ce44SJohn Forte ilhp->cmdsn = htonl(isp->sess_cmdsn);
714fcf3ce44SJohn Forte
715fcf3ce44SJohn Forte ilhp->min_version = ISCSI_DRAFT20_VERSION;
716fcf3ce44SJohn Forte ilhp->max_version = ISCSI_DRAFT20_VERSION;
717fcf3ce44SJohn Forte
718fcf3ce44SJohn Forte /*
719fcf3ce44SJohn Forte * we have to send 0 until full-feature stage
720fcf3ce44SJohn Forte */
721fcf3ce44SJohn Forte ilhp->expstatsn = htonl(icp->conn_expstatsn);
722fcf3ce44SJohn Forte
723fcf3ce44SJohn Forte /*
724fcf3ce44SJohn Forte * the very first Login PDU has some additional requirements,
725fcf3ce44SJohn Forte * * and we need to decide what stage to start in.
726fcf3ce44SJohn Forte */
727fcf3ce44SJohn Forte if (icp->conn_current_stage == ISCSI_INITIAL_LOGIN_STAGE) {
728fcf3ce44SJohn Forte if ((isp->sess_hba->hba_name) &&
729fcf3ce44SJohn Forte (isp->sess_hba->hba_name[0])) {
73030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
731fcf3ce44SJohn Forte "InitiatorName",
732fcf3ce44SJohn Forte (char *)isp->sess_hba->hba_name)) {
733fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
734fcf3ce44SJohn Forte }
735fcf3ce44SJohn Forte } else {
736fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
737fcf3ce44SJohn Forte "failed - initiator name is required",
738fcf3ce44SJohn Forte icp->conn_oid);
739fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
740fcf3ce44SJohn Forte }
741fcf3ce44SJohn Forte
742fcf3ce44SJohn Forte if ((isp->sess_hba->hba_alias) &&
743fcf3ce44SJohn Forte (isp->sess_hba->hba_alias[0])) {
74430e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
745fcf3ce44SJohn Forte "InitiatorAlias",
746fcf3ce44SJohn Forte (char *)isp->sess_hba->hba_alias)) {
747fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
748fcf3ce44SJohn Forte }
749fcf3ce44SJohn Forte }
750fcf3ce44SJohn Forte
751fcf3ce44SJohn Forte if (isp->sess_type == ISCSI_SESS_TYPE_NORMAL) {
752fcf3ce44SJohn Forte if (isp->sess_name[0] != '\0') {
75330e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
754fcf3ce44SJohn Forte "TargetName", (char *)isp->sess_name)) {
755fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
756fcf3ce44SJohn Forte }
757fcf3ce44SJohn Forte }
758fcf3ce44SJohn Forte
75930e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
760fcf3ce44SJohn Forte "SessionType", "Normal")) {
761fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
762fcf3ce44SJohn Forte }
763fcf3ce44SJohn Forte } else if (isp->sess_type == ISCSI_SESS_TYPE_DISCOVERY) {
76430e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
765fcf3ce44SJohn Forte "SessionType", "Discovery")) {
766fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
767fcf3ce44SJohn Forte }
768fcf3ce44SJohn Forte } else {
769fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
770fcf3ce44SJohn Forte }
771fcf3ce44SJohn Forte
772fcf3ce44SJohn Forte if (auth_client) {
773fcf3ce44SJohn Forte /* we're prepared to do authentication */
774fcf3ce44SJohn Forte icp->conn_current_stage =
775fcf3ce44SJohn Forte ISCSI_SECURITY_NEGOTIATION_STAGE;
776fcf3ce44SJohn Forte } else {
777fcf3ce44SJohn Forte /* can't do any authentication, skip that stage */
778fcf3ce44SJohn Forte icp->conn_current_stage =
779fcf3ce44SJohn Forte ISCSI_OP_PARMS_NEGOTIATION_STAGE;
780fcf3ce44SJohn Forte }
781fcf3ce44SJohn Forte }
782fcf3ce44SJohn Forte
783fcf3ce44SJohn Forte /*
784fcf3ce44SJohn Forte * fill in text based on the stage
785fcf3ce44SJohn Forte */
786fcf3ce44SJohn Forte switch (icp->conn_current_stage) {
787fcf3ce44SJohn Forte case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
788fcf3ce44SJohn Forte /*
789fcf3ce44SJohn Forte * we always try to go from op params to full
790fcf3ce44SJohn Forte * feature stage
791fcf3ce44SJohn Forte */
792fcf3ce44SJohn Forte icp->conn_next_stage = ISCSI_FULL_FEATURE_PHASE;
793fcf3ce44SJohn Forte transit = 1;
794fcf3ce44SJohn Forte
795fcf3ce44SJohn Forte /*
796fcf3ce44SJohn Forte * The terminology here may have gotten dated. A partial
797fcf3ce44SJohn Forte * response is a login response that doesn't complete a
798fcf3ce44SJohn Forte * login. If we haven't gotten a partial response, then
799fcf3ce44SJohn Forte * either we shouldn't be here, or we just switched to
800fcf3ce44SJohn Forte * this stage, and need to start offering keys.
801fcf3ce44SJohn Forte */
802fcf3ce44SJohn Forte if (!icp->conn_partial_response) {
803fcf3ce44SJohn Forte /*
804fcf3ce44SJohn Forte * request the desired settings the first time
805fcf3ce44SJohn Forte * we are in this stage
806fcf3ce44SJohn Forte */
807fcf3ce44SJohn Forte switch (icp->conn_params.header_digest) {
808fcf3ce44SJohn Forte case ISCSI_DIGEST_NONE:
80930e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
810fcf3ce44SJohn Forte max_data_length, "HeaderDigest", "None")) {
811fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
812fcf3ce44SJohn Forte }
813fcf3ce44SJohn Forte break;
814fcf3ce44SJohn Forte case ISCSI_DIGEST_CRC32C:
81530e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
816fcf3ce44SJohn Forte max_data_length,
817fcf3ce44SJohn Forte "HeaderDigest", "CRC32C")) {
818fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
819fcf3ce44SJohn Forte }
820fcf3ce44SJohn Forte break;
821fcf3ce44SJohn Forte case ISCSI_DIGEST_CRC32C_NONE:
82230e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
823fcf3ce44SJohn Forte max_data_length, "HeaderDigest",
824fcf3ce44SJohn Forte "CRC32C,None")) {
825fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
826fcf3ce44SJohn Forte }
827fcf3ce44SJohn Forte break;
828fcf3ce44SJohn Forte default:
829fcf3ce44SJohn Forte case ISCSI_DIGEST_NONE_CRC32C:
83030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
831fcf3ce44SJohn Forte max_data_length, "HeaderDigest",
832fcf3ce44SJohn Forte "None,CRC32C")) {
833fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
834fcf3ce44SJohn Forte }
835fcf3ce44SJohn Forte break;
836fcf3ce44SJohn Forte }
837fcf3ce44SJohn Forte
838fcf3ce44SJohn Forte switch (icp->conn_params.data_digest) {
839fcf3ce44SJohn Forte case ISCSI_DIGEST_NONE:
84030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
841fcf3ce44SJohn Forte max_data_length, "DataDigest", "None")) {
842fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
843fcf3ce44SJohn Forte }
844fcf3ce44SJohn Forte break;
845fcf3ce44SJohn Forte case ISCSI_DIGEST_CRC32C:
84630e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
847fcf3ce44SJohn Forte max_data_length, "DataDigest", "CRC32C")) {
848fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
849fcf3ce44SJohn Forte }
850fcf3ce44SJohn Forte break;
851fcf3ce44SJohn Forte case ISCSI_DIGEST_CRC32C_NONE:
85230e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
853fcf3ce44SJohn Forte max_data_length, "DataDigest",
854fcf3ce44SJohn Forte "CRC32C,None")) {
855fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
856fcf3ce44SJohn Forte }
857fcf3ce44SJohn Forte break;
858fcf3ce44SJohn Forte default:
859fcf3ce44SJohn Forte case ISCSI_DIGEST_NONE_CRC32C:
86030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
861fcf3ce44SJohn Forte max_data_length, "DataDigest",
862fcf3ce44SJohn Forte "None,CRC32C")) {
863fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
864fcf3ce44SJohn Forte }
865fcf3ce44SJohn Forte break;
866fcf3ce44SJohn Forte }
867fcf3ce44SJohn Forte
868fcf3ce44SJohn Forte (void) sprintf(value, "%d",
869fcf3ce44SJohn Forte icp->conn_params.max_recv_data_seg_len);
87030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
871fcf3ce44SJohn Forte "MaxRecvDataSegmentLength", value)) {
872fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
873fcf3ce44SJohn Forte }
874fcf3ce44SJohn Forte
875fcf3ce44SJohn Forte (void) sprintf(value, "%d",
876fcf3ce44SJohn Forte icp->conn_params.default_time_to_wait);
87730e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
878fcf3ce44SJohn Forte max_data_length, "DefaultTime2Wait", value)) {
879fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
880fcf3ce44SJohn Forte }
881fcf3ce44SJohn Forte
882fcf3ce44SJohn Forte (void) sprintf(value, "%d",
883fcf3ce44SJohn Forte icp->conn_params.default_time_to_retain);
88430e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
885fcf3ce44SJohn Forte max_data_length, "DefaultTime2Retain", value)) {
886fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
887fcf3ce44SJohn Forte }
888fcf3ce44SJohn Forte
889fcf3ce44SJohn Forte (void) sprintf(value, "%d",
890fcf3ce44SJohn Forte icp->conn_params.error_recovery_level);
89130e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
892fcf3ce44SJohn Forte max_data_length, "ErrorRecoveryLevel", "0")) {
893fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
894fcf3ce44SJohn Forte }
895fcf3ce44SJohn Forte
89630e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
897fcf3ce44SJohn Forte max_data_length, "IFMarker",
898fcf3ce44SJohn Forte icp->conn_params.ifmarker ? "Yes" : "No")) {
899fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
900fcf3ce44SJohn Forte }
901fcf3ce44SJohn Forte
90230e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
903fcf3ce44SJohn Forte max_data_length, "OFMarker",
904fcf3ce44SJohn Forte icp->conn_params.ofmarker ? "Yes" : "No")) {
905fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
906fcf3ce44SJohn Forte }
907fcf3ce44SJohn Forte
908fcf3ce44SJohn Forte /*
909fcf3ce44SJohn Forte * The following login parameters are "Irrelevant"
910fcf3ce44SJohn Forte * for discovery sessions
911fcf3ce44SJohn Forte */
912fcf3ce44SJohn Forte if (isp->sess_type != ISCSI_SESS_TYPE_DISCOVERY) {
913fcf3ce44SJohn Forte
91430e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
915fcf3ce44SJohn Forte max_data_length, "InitialR2T",
916fcf3ce44SJohn Forte icp->conn_params.initial_r2t ?
917fcf3ce44SJohn Forte "Yes" : "No")) {
918fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
919fcf3ce44SJohn Forte }
920fcf3ce44SJohn Forte
92130e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
922fcf3ce44SJohn Forte max_data_length, "ImmediateData",
923fcf3ce44SJohn Forte icp->conn_params.immediate_data ?
924fcf3ce44SJohn Forte "Yes" : "No")) {
925fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
926fcf3ce44SJohn Forte }
927fcf3ce44SJohn Forte
928fcf3ce44SJohn Forte (void) sprintf(value, "%d",
929fcf3ce44SJohn Forte icp->conn_params.max_burst_length);
93030e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
931fcf3ce44SJohn Forte max_data_length, "MaxBurstLength", value)) {
932fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
933fcf3ce44SJohn Forte }
934fcf3ce44SJohn Forte
935fcf3ce44SJohn Forte (void) sprintf(value, "%d",
936fcf3ce44SJohn Forte icp->conn_params.first_burst_length);
93730e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
938fcf3ce44SJohn Forte "FirstBurstLength", value)) {
939fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
940fcf3ce44SJohn Forte }
941fcf3ce44SJohn Forte
942fcf3ce44SJohn Forte (void) sprintf(value, "%d",
943fcf3ce44SJohn Forte icp->conn_params.max_outstanding_r2t);
94430e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
945fcf3ce44SJohn Forte "MaxOutstandingR2T", value)) {
946fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
947fcf3ce44SJohn Forte }
948fcf3ce44SJohn Forte
949fcf3ce44SJohn Forte (void) sprintf(value, "%d",
950fcf3ce44SJohn Forte icp->conn_params.max_connections);
95130e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu, max_data_length,
952fcf3ce44SJohn Forte "MaxConnections", value)) {
953fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
954fcf3ce44SJohn Forte }
955fcf3ce44SJohn Forte
95630e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
957fcf3ce44SJohn Forte max_data_length, "DataPDUInOrder",
958fcf3ce44SJohn Forte icp->conn_params.data_pdu_in_order ?
959fcf3ce44SJohn Forte "Yes" : "No")) {
960fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
961fcf3ce44SJohn Forte }
962fcf3ce44SJohn Forte
96330e7468fSPeter Dunlap if (!iscsi_add_text(text_pdu,
964fcf3ce44SJohn Forte max_data_length, "DataSequenceInOrder",
965fcf3ce44SJohn Forte icp->conn_params.data_sequence_in_order ?
966fcf3ce44SJohn Forte "Yes" : "No")) {
967fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
968fcf3ce44SJohn Forte }
969fcf3ce44SJohn Forte }
970fcf3ce44SJohn Forte }
971fcf3ce44SJohn Forte break;
972fcf3ce44SJohn Forte
973fcf3ce44SJohn Forte case ISCSI_SECURITY_NEGOTIATION_STAGE:
974fcf3ce44SJohn Forte keytype = iscsiAuthKeyTypeNone;
975fcf3ce44SJohn Forte rc = iscsiAuthClientSendTransitBit(auth_client, &transit);
976fcf3ce44SJohn Forte
977fcf3ce44SJohn Forte /*
978fcf3ce44SJohn Forte * see if we're ready for a stage change
979fcf3ce44SJohn Forte */
980fcf3ce44SJohn Forte if (rc == iscsiAuthStatusNoError) {
981fcf3ce44SJohn Forte if (transit) {
982fcf3ce44SJohn Forte icp->conn_next_stage =
983fcf3ce44SJohn Forte ISCSI_OP_PARMS_NEGOTIATION_STAGE;
984fcf3ce44SJohn Forte } else {
985fcf3ce44SJohn Forte icp->conn_next_stage =
986fcf3ce44SJohn Forte ISCSI_SECURITY_NEGOTIATION_STAGE;
987fcf3ce44SJohn Forte }
988fcf3ce44SJohn Forte } else {
989fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
990fcf3ce44SJohn Forte }
991fcf3ce44SJohn Forte
992fcf3ce44SJohn Forte /*
993fcf3ce44SJohn Forte * enumerate all the keys the auth code might want to send
994fcf3ce44SJohn Forte */
995fcf3ce44SJohn Forte while (iscsiAuthClientGetNextKeyType(&keytype) ==
996fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
997fcf3ce44SJohn Forte int present = 0;
998fcf3ce44SJohn Forte char *key = (char *)iscsiAuthClientGetKeyName(keytype);
999fcf3ce44SJohn Forte int key_length = key ? strlen(key) : 0;
100030e7468fSPeter Dunlap int pdu_length = text_pdu->isp_datalen;
1001fcf3ce44SJohn Forte char *auth_value = data + pdu_length + key_length + 1;
1002fcf3ce44SJohn Forte unsigned int max_length = max_data_length -
1003fcf3ce44SJohn Forte (pdu_length + key_length + 1);
1004fcf3ce44SJohn Forte
1005fcf3ce44SJohn Forte /*
1006fcf3ce44SJohn Forte * add the key/value pairs the auth code wants to
1007fcf3ce44SJohn Forte * send directly to the PDU, since they could in
1008fcf3ce44SJohn Forte * theory be large.
1009fcf3ce44SJohn Forte */
1010fcf3ce44SJohn Forte rc = iscsiAuthClientSendKeyValue(auth_client, keytype,
1011fcf3ce44SJohn Forte &present, auth_value, max_length);
1012fcf3ce44SJohn Forte if ((rc == iscsiAuthStatusNoError) && present) {
1013fcf3ce44SJohn Forte /*
1014fcf3ce44SJohn Forte * actually fill in the key
1015fcf3ce44SJohn Forte */
1016fcf3ce44SJohn Forte (void) strncpy(&data[pdu_length], key,
1017fcf3ce44SJohn Forte key_length);
1018fcf3ce44SJohn Forte pdu_length += key_length;
1019fcf3ce44SJohn Forte data[pdu_length] = '=';
1020fcf3ce44SJohn Forte pdu_length++;
1021fcf3ce44SJohn Forte /*
1022fcf3ce44SJohn Forte * adjust the PDU's data segment length to
1023fcf3ce44SJohn Forte * include the value and trailing NULL
1024fcf3ce44SJohn Forte */
1025fcf3ce44SJohn Forte pdu_length += strlen(auth_value) + 1;
102630e7468fSPeter Dunlap text_pdu->isp_datalen = pdu_length;
1027fcf3ce44SJohn Forte hton24(ihp->dlength, pdu_length);
1028fcf3ce44SJohn Forte }
1029fcf3ce44SJohn Forte }
1030fcf3ce44SJohn Forte
1031fcf3ce44SJohn Forte break;
1032fcf3ce44SJohn Forte case ISCSI_FULL_FEATURE_PHASE:
1033fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1034fcf3ce44SJohn Forte "failed - can't send login in full feature stage",
1035fcf3ce44SJohn Forte icp->conn_oid);
1036fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1037fcf3ce44SJohn Forte default:
1038fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1039fcf3ce44SJohn Forte "failed - can't send login in unknown stage (%d)",
1040fcf3ce44SJohn Forte icp->conn_oid, icp->conn_current_stage);
1041fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1042fcf3ce44SJohn Forte }
1043fcf3ce44SJohn Forte
1044fcf3ce44SJohn Forte /* fill in the flags */
1045fcf3ce44SJohn Forte ilhp->flags = icp->conn_current_stage << 2;
1046fcf3ce44SJohn Forte if (transit) {
1047fcf3ce44SJohn Forte /* transit to the next stage */
1048fcf3ce44SJohn Forte ilhp->flags |= icp->conn_next_stage;
1049fcf3ce44SJohn Forte ilhp->flags |= ISCSI_FLAG_LOGIN_TRANSIT;
1050fcf3ce44SJohn Forte } else {
1051fcf3ce44SJohn Forte /* next == current */
1052fcf3ce44SJohn Forte ilhp->flags |= icp->conn_current_stage;
1053fcf3ce44SJohn Forte }
1054fcf3ce44SJohn Forte
1055fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
1056fcf3ce44SJohn Forte }
1057fcf3ce44SJohn Forte
1058fcf3ce44SJohn Forte
1059fcf3ce44SJohn Forte /*
1060fcf3ce44SJohn Forte * iscsi_process_login_response - This assumes the text data is
1061fcf3ce44SJohn Forte * always NUL terminated. The caller can always arrange for that by
1062fcf3ce44SJohn Forte * using a slightly larger buffer than the max PDU size, and then
1063fcf3ce44SJohn Forte * appending a NUL to the PDU.
1064fcf3ce44SJohn Forte */
1065fcf3ce44SJohn Forte static iscsi_status_t
iscsi_process_login_response(iscsi_conn_t * icp,iscsi_login_rsp_hdr_t * ilrhp,char * data,int max_data_length)1066fcf3ce44SJohn Forte iscsi_process_login_response(iscsi_conn_t *icp,
1067fcf3ce44SJohn Forte iscsi_login_rsp_hdr_t *ilrhp, char *data, int max_data_length)
1068fcf3ce44SJohn Forte {
1069fcf3ce44SJohn Forte iscsi_sess_t *isp = NULL;
1070fcf3ce44SJohn Forte IscsiAuthClient *auth_client = NULL;
1071fcf3ce44SJohn Forte int transit = 0;
1072fcf3ce44SJohn Forte char *text = data;
1073fcf3ce44SJohn Forte char *end = NULL;
1074fcf3ce44SJohn Forte int pdu_current_stage = 0;
1075fcf3ce44SJohn Forte int pdu_next_stage = 0;
1076fcf3ce44SJohn Forte int debug_status = 0;
1077fcf3ce44SJohn Forte unsigned long tmp;
1078fcf3ce44SJohn Forte char *tmpe;
1079fcf3ce44SJohn Forte boolean_t fbl_irrelevant = B_FALSE;
1080fcf3ce44SJohn Forte
1081fcf3ce44SJohn Forte ASSERT(icp != NULL);
1082fcf3ce44SJohn Forte ASSERT(ilrhp != NULL);
1083fcf3ce44SJohn Forte ASSERT(data != NULL);
1084fcf3ce44SJohn Forte isp = icp->conn_sess;
1085fcf3ce44SJohn Forte ASSERT(isp != NULL);
1086fcf3ce44SJohn Forte
1087fcf3ce44SJohn Forte auth_client =
1088fcf3ce44SJohn Forte (isp->sess_auth.auth_buffers && isp->sess_auth.num_auth_buffers) ?
1089fcf3ce44SJohn Forte (IscsiAuthClient *) isp->sess_auth.auth_buffers[0].address : NULL;
1090fcf3ce44SJohn Forte transit = ilrhp->flags & ISCSI_FLAG_LOGIN_TRANSIT;
1091fcf3ce44SJohn Forte
1092fcf3ce44SJohn Forte /* verify the initial buffer was big enough to hold everything */
1093fcf3ce44SJohn Forte end = text + ntoh24(ilrhp->dlength) + 1;
1094fcf3ce44SJohn Forte if (end >= (data + max_data_length)) {
1095fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1096fcf3ce44SJohn Forte "buffer too small", icp->conn_oid);
1097fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1098fcf3ce44SJohn Forte }
1099fcf3ce44SJohn Forte *end = '\0';
1100fcf3ce44SJohn Forte
1101fcf3ce44SJohn Forte /* if the response status was success, sanity check the response */
1102fcf3ce44SJohn Forte if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1103fcf3ce44SJohn Forte /* check the active version */
1104fcf3ce44SJohn Forte if (ilrhp->active_version != ISCSI_DRAFT20_VERSION) {
1105fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1106fcf3ce44SJohn Forte "failed - target version incompatible "
1107fcf3ce44SJohn Forte "received:0x%0x2x expected:0x%02x",
1108fcf3ce44SJohn Forte icp->conn_oid, ilrhp->active_version,
1109fcf3ce44SJohn Forte ISCSI_DRAFT20_VERSION);
1110fcf3ce44SJohn Forte return (ISCSI_STATUS_VERSION_MISMATCH);
1111fcf3ce44SJohn Forte }
1112fcf3ce44SJohn Forte
1113fcf3ce44SJohn Forte /* make sure the current stage matches */
1114fcf3ce44SJohn Forte pdu_current_stage = (ilrhp->flags &
1115fcf3ce44SJohn Forte ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2;
1116fcf3ce44SJohn Forte if (pdu_current_stage != icp->conn_current_stage) {
1117fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1118fcf3ce44SJohn Forte "failed - login response contained invalid "
1119fcf3ce44SJohn Forte "stage %d", icp->conn_oid, pdu_current_stage);
1120fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1121fcf3ce44SJohn Forte }
1122fcf3ce44SJohn Forte
1123fcf3ce44SJohn Forte /*
1124fcf3ce44SJohn Forte * Make sure that we're actually advancing
1125fcf3ce44SJohn Forte * if the T-bit is set
1126fcf3ce44SJohn Forte */
1127fcf3ce44SJohn Forte pdu_next_stage = ilrhp->flags &
1128fcf3ce44SJohn Forte ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1129fcf3ce44SJohn Forte if (transit && (pdu_next_stage <= icp->conn_current_stage)) {
1130fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1131fcf3ce44SJohn Forte "failed - login response wants to go to stage "
1132fcf3ce44SJohn Forte "%d, but we want stage %d", icp->conn_oid,
1133fcf3ce44SJohn Forte pdu_next_stage, icp->conn_next_stage);
1134fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1135fcf3ce44SJohn Forte }
1136fcf3ce44SJohn Forte }
1137fcf3ce44SJohn Forte
1138fcf3ce44SJohn Forte if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1139fcf3ce44SJohn Forte if (iscsiAuthClientRecvBegin(auth_client) !=
1140fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
1141fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1142fcf3ce44SJohn Forte "authentication receive failed", icp->conn_oid);
1143fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1144fcf3ce44SJohn Forte }
1145fcf3ce44SJohn Forte
1146fcf3ce44SJohn Forte if (iscsiAuthClientRecvTransitBit(auth_client,
1147fcf3ce44SJohn Forte transit) != iscsiAuthStatusNoError) {
1148fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1149fcf3ce44SJohn Forte "authentication transmit failed", icp->conn_oid);
1150fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1151fcf3ce44SJohn Forte }
1152fcf3ce44SJohn Forte }
1153fcf3ce44SJohn Forte
1154fcf3ce44SJohn Forte /*
1155fcf3ce44SJohn Forte * scan the text data
1156fcf3ce44SJohn Forte */
1157fcf3ce44SJohn Forte more_text:
1158fcf3ce44SJohn Forte while (text && (text < end)) {
1159fcf3ce44SJohn Forte char *value = NULL;
1160fcf3ce44SJohn Forte char *value_end = NULL;
1161fcf3ce44SJohn Forte
1162fcf3ce44SJohn Forte /*
1163fcf3ce44SJohn Forte * skip any NULs separating each text key=value pair
1164fcf3ce44SJohn Forte */
1165fcf3ce44SJohn Forte while ((text < end) && (*text == '\0')) {
1166fcf3ce44SJohn Forte text++;
1167fcf3ce44SJohn Forte }
1168fcf3ce44SJohn Forte if (text >= end) {
1169fcf3ce44SJohn Forte break;
1170fcf3ce44SJohn Forte }
1171fcf3ce44SJohn Forte
1172fcf3ce44SJohn Forte /*
1173fcf3ce44SJohn Forte * handle keys appropriate for each stage
1174fcf3ce44SJohn Forte */
1175fcf3ce44SJohn Forte switch (icp->conn_current_stage) {
1176fcf3ce44SJohn Forte case ISCSI_SECURITY_NEGOTIATION_STAGE:
1177fcf3ce44SJohn Forte /*
1178fcf3ce44SJohn Forte * a few keys are possible in Security stage
1179fcf3ce44SJohn Forte * * which the auth code doesn't care about,
1180fcf3ce44SJohn Forte * * but which we might want to see, or at
1181fcf3ce44SJohn Forte * * least not choke on.
1182fcf3ce44SJohn Forte */
1183fcf3ce44SJohn Forte if (iscsi_find_key_value("TargetAlias",
1184fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1185fcf3ce44SJohn Forte isp->sess_alias_length =
1186fcf3ce44SJohn Forte sizeof (isp->sess_alias) - 1;
1187fcf3ce44SJohn Forte
1188fcf3ce44SJohn Forte if ((value_end - value) <
1189fcf3ce44SJohn Forte isp->sess_alias_length) {
1190fcf3ce44SJohn Forte isp->sess_alias_length =
1191fcf3ce44SJohn Forte value_end - value;
1192fcf3ce44SJohn Forte }
1193fcf3ce44SJohn Forte
1194fcf3ce44SJohn Forte bcopy(value, isp->sess_alias,
1195fcf3ce44SJohn Forte isp->sess_alias_length);
1196fcf3ce44SJohn Forte isp->sess_alias[isp->sess_alias_length + 1] =
1197fcf3ce44SJohn Forte '\0';
1198fcf3ce44SJohn Forte text = value_end;
1199fcf3ce44SJohn Forte
1200fcf3ce44SJohn Forte } else if (iscsi_find_key_value("TargetAddress",
1201fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1202fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_update_address(
1203fcf3ce44SJohn Forte icp, value))) {
1204fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1205fcf3ce44SJohn Forte "login failed - login redirection "
1206fcf3ce44SJohn Forte "invalid", icp->conn_oid);
1207fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1208fcf3ce44SJohn Forte }
1209fcf3ce44SJohn Forte text = value_end;
1210fcf3ce44SJohn Forte } else if (iscsi_find_key_value("TargetPortalGroupTag",
1211fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1212fcf3ce44SJohn Forte /*
1213fcf3ce44SJohn Forte * We should have already obtained this via
1214fcf3ce44SJohn Forte * discovery. We've already picked an isid,
1215fcf3ce44SJohn Forte * so the most we can do is confirm we reached
1216fcf3ce44SJohn Forte * the portal group we were expecting to.
1217fcf3ce44SJohn Forte */
1218fcf3ce44SJohn Forte if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1219fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1220fcf3ce44SJohn Forte }
1221fcf3ce44SJohn Forte if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1222fcf3ce44SJohn Forte if (tmp != isp->sess_tpgt_conf) {
1223fcf3ce44SJohn Forte
1224fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - target "
1225fcf3ce44SJohn Forte "protocol group tag mismatch, expected %d, received %lu",
1226fcf3ce44SJohn Forte icp->conn_oid, isp->sess_tpgt_conf, tmp);
1227cc7ef495Syi zhang - Sun Microsystems - Beijing China return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
1228fcf3ce44SJohn Forte
1229fcf3ce44SJohn Forte }
1230fcf3ce44SJohn Forte }
1231fcf3ce44SJohn Forte isp->sess_tpgt_nego = (int)tmp;
1232fcf3ce44SJohn Forte text = value_end;
1233fcf3ce44SJohn Forte } else {
1234fcf3ce44SJohn Forte /*
1235fcf3ce44SJohn Forte * any key we don't recognize either goes
1236fcf3ce44SJohn Forte * to the auth code, or we choke on it
1237fcf3ce44SJohn Forte */
1238fcf3ce44SJohn Forte int keytype = iscsiAuthKeyTypeNone;
1239fcf3ce44SJohn Forte
1240fcf3ce44SJohn Forte while (iscsiAuthClientGetNextKeyType(
1241fcf3ce44SJohn Forte &keytype) == iscsiAuthStatusNoError) {
1242fcf3ce44SJohn Forte
1243fcf3ce44SJohn Forte char *key =
1244fcf3ce44SJohn Forte (char *)iscsiAuthClientGetKeyName(
1245fcf3ce44SJohn Forte keytype);
1246fcf3ce44SJohn Forte
1247fcf3ce44SJohn Forte if ((key) &&
1248fcf3ce44SJohn Forte (iscsi_find_key_value(key,
1249fcf3ce44SJohn Forte text, end, &value, &value_end))) {
1250fcf3ce44SJohn Forte
1251fcf3ce44SJohn Forte if (iscsiAuthClientRecvKeyValue
1252fcf3ce44SJohn Forte (auth_client, keytype,
1253fcf3ce44SJohn Forte value) !=
1254fcf3ce44SJohn Forte iscsiAuthStatusNoError) {
1255fcf3ce44SJohn Forte
1256fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't accept "
1257fcf3ce44SJohn Forte "%s in security stage", icp->conn_oid, text);
1258fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1259fcf3ce44SJohn Forte
1260fcf3ce44SJohn Forte }
1261fcf3ce44SJohn Forte text = value_end;
1262fcf3ce44SJohn Forte goto more_text;
1263fcf3ce44SJohn Forte }
1264fcf3ce44SJohn Forte }
1265fcf3ce44SJohn Forte
1266fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - can't except "
1267fcf3ce44SJohn Forte "%s in security stage", icp->conn_oid, text);
1268fcf3ce44SJohn Forte
1269fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1270fcf3ce44SJohn Forte }
1271fcf3ce44SJohn Forte break;
1272fcf3ce44SJohn Forte case ISCSI_OP_PARMS_NEGOTIATION_STAGE:
1273fcf3ce44SJohn Forte if (iscsi_find_key_value("TargetAlias", text,
1274fcf3ce44SJohn Forte end, &value, &value_end)) {
1275fcf3ce44SJohn Forte isp->sess_alias_length =
1276fcf3ce44SJohn Forte sizeof (isp->sess_alias) - 1;
1277fcf3ce44SJohn Forte
1278fcf3ce44SJohn Forte if ((value_end - value) <
1279fcf3ce44SJohn Forte isp->sess_alias_length) {
1280fcf3ce44SJohn Forte isp->sess_alias_length =
1281fcf3ce44SJohn Forte value_end - value;
1282fcf3ce44SJohn Forte }
1283fcf3ce44SJohn Forte
1284fcf3ce44SJohn Forte bcopy(value, isp->sess_alias,
1285fcf3ce44SJohn Forte isp->sess_alias_length);
1286fcf3ce44SJohn Forte isp->sess_alias[isp->sess_alias_length + 1] =
1287fcf3ce44SJohn Forte '\0';
1288fcf3ce44SJohn Forte text = value_end;
1289fcf3ce44SJohn Forte
1290fcf3ce44SJohn Forte } else if (iscsi_find_key_value("TargetAddress",
1291fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1292fcf3ce44SJohn Forte if (!ISCSI_SUCCESS(iscsi_update_address(
1293fcf3ce44SJohn Forte icp, value))) {
1294fcf3ce44SJohn Forte
1295fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - login "
1296fcf3ce44SJohn Forte "redirection invalid", icp->conn_oid);
1297fcf3ce44SJohn Forte
1298fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1299fcf3ce44SJohn Forte }
1300fcf3ce44SJohn Forte text = value_end;
1301fcf3ce44SJohn Forte } else if (iscsi_find_key_value("TargetPortalGroupTag",
1302fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1303fcf3ce44SJohn Forte /*
1304fcf3ce44SJohn Forte * We should have already obtained this via
1305fcf3ce44SJohn Forte * discovery. We've already picked an isid,
1306fcf3ce44SJohn Forte * so the most we can do is confirm we reached
1307fcf3ce44SJohn Forte * the portal group we were expecting to.
1308fcf3ce44SJohn Forte */
1309fcf3ce44SJohn Forte if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1310fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1311fcf3ce44SJohn Forte }
1312fcf3ce44SJohn Forte if (isp->sess_tpgt_conf != ISCSI_DEFAULT_TPGT) {
1313fcf3ce44SJohn Forte if (tmp != isp->sess_tpgt_conf) {
1314fcf3ce44SJohn Forte
1315fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - target portal "
1316fcf3ce44SJohn Forte "tag mismatch, expected:%d received:%lu", icp->conn_oid,
1317fcf3ce44SJohn Forte isp->sess_tpgt_conf, tmp);
1318cc7ef495Syi zhang - Sun Microsystems - Beijing China return (ISCSI_STATUS_LOGIN_TPGT_NEGO_FAIL);
1319fcf3ce44SJohn Forte
1320fcf3ce44SJohn Forte }
1321fcf3ce44SJohn Forte }
1322fcf3ce44SJohn Forte isp->sess_tpgt_nego = (int)tmp;
1323fcf3ce44SJohn Forte text = value_end;
1324fcf3ce44SJohn Forte
1325fcf3ce44SJohn Forte } else if (iscsi_find_key_value("InitialR2T",
1326fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1327fcf3ce44SJohn Forte
1328fcf3ce44SJohn Forte /*
1329fcf3ce44SJohn Forte * iSCSI RFC section 12.10 states that
1330fcf3ce44SJohn Forte * InitialR2T is Irrelevant for a
1331fcf3ce44SJohn Forte * discovery session.
1332fcf3ce44SJohn Forte */
1333fcf3ce44SJohn Forte if (isp->sess_type ==
1334fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1335fcf3ce44SJohn Forte /* EMPTY */
1336fcf3ce44SJohn Forte } else if (value == NULL) {
1337fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1338fcf3ce44SJohn Forte "login failed - InitialR2T is "
1339fcf3ce44SJohn Forte "invalid - protocol error",
1340fcf3ce44SJohn Forte icp->conn_oid);
1341fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1342fcf3ce44SJohn Forte } else if (strcmp(value, "Yes") == 0) {
1343fcf3ce44SJohn Forte icp->conn_params.initial_r2t = B_TRUE;
1344fcf3ce44SJohn Forte } else if (strcmp(value, "No") == 0) {
1345fcf3ce44SJohn Forte icp->conn_params.initial_r2t = B_FALSE;
1346fcf3ce44SJohn Forte } else {
1347fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1348fcf3ce44SJohn Forte "login failed - InitialR2T is "
1349fcf3ce44SJohn Forte "invalid - protocol error",
1350fcf3ce44SJohn Forte icp->conn_oid);
1351fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1352fcf3ce44SJohn Forte }
1353fcf3ce44SJohn Forte text = value_end;
1354fcf3ce44SJohn Forte
1355fcf3ce44SJohn Forte } else if (iscsi_find_key_value("ImmediateData",
1356fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1357fcf3ce44SJohn Forte
1358fcf3ce44SJohn Forte /*
1359fcf3ce44SJohn Forte * iSCSI RFC section 12.11 states that
1360fcf3ce44SJohn Forte * ImmediateData is Irrelevant for a
1361fcf3ce44SJohn Forte * discovery session.
1362fcf3ce44SJohn Forte */
1363fcf3ce44SJohn Forte if (isp->sess_type ==
1364fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1365fcf3ce44SJohn Forte /* EMPTY */
1366fcf3ce44SJohn Forte } else if (value == NULL) {
1367fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1368fcf3ce44SJohn Forte "login failed - ImmediateData is "
1369fcf3ce44SJohn Forte "invalid - protocol error",
1370fcf3ce44SJohn Forte icp->conn_oid);
1371fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1372fcf3ce44SJohn Forte } else if (strcmp(value, "Yes") == 0) {
1373fcf3ce44SJohn Forte icp->conn_params.immediate_data = 1;
1374fcf3ce44SJohn Forte } else if (strcmp(value, "No") == 0) {
1375fcf3ce44SJohn Forte icp->conn_params.immediate_data = 0;
1376fcf3ce44SJohn Forte } else {
1377fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1378fcf3ce44SJohn Forte "login failed - ImmediateData is "
1379fcf3ce44SJohn Forte "invalid - protocol error",
1380fcf3ce44SJohn Forte icp->conn_oid);
1381fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1382fcf3ce44SJohn Forte }
1383fcf3ce44SJohn Forte text = value_end;
1384fcf3ce44SJohn Forte
1385fcf3ce44SJohn Forte } else if (iscsi_find_key_value(
1386fcf3ce44SJohn Forte "MaxRecvDataSegmentLength", text, end,
1387fcf3ce44SJohn Forte &value, &value_end)) {
1388fcf3ce44SJohn Forte
1389fcf3ce44SJohn Forte if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1390fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1391fcf3ce44SJohn Forte "login failed - MaxRecvDataSegment"
1392fcf3ce44SJohn Forte "Length is invalid - protocol "
1393fcf3ce44SJohn Forte "error", icp->conn_oid);
1394fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1395fcf3ce44SJohn Forte }
1396fcf3ce44SJohn Forte icp->conn_params.max_recv_data_seg_len =
1397fcf3ce44SJohn Forte icp->conn_params.max_xmit_data_seg_len =
1398fcf3ce44SJohn Forte (int)tmp;
1399fcf3ce44SJohn Forte
1400fcf3ce44SJohn Forte text = value_end;
1401fcf3ce44SJohn Forte } else if (iscsi_find_key_value("FirstBurstLength",
1402fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1403fcf3ce44SJohn Forte
1404fcf3ce44SJohn Forte /*
1405fcf3ce44SJohn Forte * iSCSI RFC section 12.14 states that
1406fcf3ce44SJohn Forte * FirstBurstLength is Irrelevant if
1407fcf3ce44SJohn Forte * InitialR2T=Yes and ImmediateData=No
1408fcf3ce44SJohn Forte * or is this is a discovery session.
1409fcf3ce44SJohn Forte */
1410fcf3ce44SJohn Forte if ((isp->sess_type ==
1411fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY)) {
1412fcf3ce44SJohn Forte /* EMPTY */
1413fcf3ce44SJohn Forte } else if (value &&
1414fcf3ce44SJohn Forte (strcmp(value, "Irrelevant") == 0)) {
1415fcf3ce44SJohn Forte /* irrelevant */
1416fcf3ce44SJohn Forte fbl_irrelevant = B_TRUE;
1417fcf3ce44SJohn Forte } else if (ddi_strtoul(
1418fcf3ce44SJohn Forte value, &tmpe, 0, &tmp) != 0) {
1419fcf3ce44SJohn Forte /* bad value */
1420fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1421fcf3ce44SJohn Forte "login failed - FirstBurstLength"
1422fcf3ce44SJohn Forte "is invalid - protocol error",
1423fcf3ce44SJohn Forte icp->conn_oid);
1424fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1425fcf3ce44SJohn Forte } else {
1426fcf3ce44SJohn Forte /* good value */
1427fcf3ce44SJohn Forte icp->conn_params.first_burst_length =
1428fcf3ce44SJohn Forte (int)tmp;
1429fcf3ce44SJohn Forte }
1430fcf3ce44SJohn Forte text = value_end;
1431fcf3ce44SJohn Forte } else if (iscsi_find_key_value("MaxBurstLength",
1432fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1433fcf3ce44SJohn Forte /*
1434fcf3ce44SJohn Forte * iSCSI RFC section 12.13 states that
1435fcf3ce44SJohn Forte * MaxBurstLength is Irrelevant for a
1436fcf3ce44SJohn Forte * discovery session.
1437fcf3ce44SJohn Forte */
1438fcf3ce44SJohn Forte if (isp->sess_type ==
1439fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1440fcf3ce44SJohn Forte /* EMPTY */
1441fcf3ce44SJohn Forte } else if (ddi_strtoul(
1442fcf3ce44SJohn Forte value, &tmpe, 0, &tmp) != 0) {
1443fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1444fcf3ce44SJohn Forte "login failed - MaxBurstLength"
1445fcf3ce44SJohn Forte "is invalid - protocol error",
1446fcf3ce44SJohn Forte icp->conn_oid);
1447fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1448fcf3ce44SJohn Forte } else {
1449fcf3ce44SJohn Forte icp->conn_params.max_burst_length =
1450fcf3ce44SJohn Forte (int)tmp;
1451fcf3ce44SJohn Forte }
1452fcf3ce44SJohn Forte
1453fcf3ce44SJohn Forte text = value_end;
1454fcf3ce44SJohn Forte
1455fcf3ce44SJohn Forte } else if (iscsi_find_key_value("HeaderDigest",
1456fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1457fcf3ce44SJohn Forte
1458fcf3ce44SJohn Forte if (strcmp(value, "None") == 0) {
1459fcf3ce44SJohn Forte if (icp->conn_params.header_digest !=
1460fcf3ce44SJohn Forte ISCSI_DIGEST_CRC32C) {
1461fcf3ce44SJohn Forte icp->conn_params.header_digest =
1462fcf3ce44SJohn Forte ISCSI_DIGEST_NONE;
1463fcf3ce44SJohn Forte } else {
1464fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi "
1465fcf3ce44SJohn Forte "connection(%u) login "
1466fcf3ce44SJohn Forte "failed - HeaderDigest="
1467fcf3ce44SJohn Forte "CRC32 is required, can't "
1468fcf3ce44SJohn Forte "accept %s",
1469fcf3ce44SJohn Forte icp->conn_oid, text);
1470fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1471fcf3ce44SJohn Forte }
1472fcf3ce44SJohn Forte } else if (strcmp(value, "CRC32C") == 0) {
1473fcf3ce44SJohn Forte if (icp->conn_params.header_digest !=
1474fcf3ce44SJohn Forte ISCSI_DIGEST_NONE) {
1475fcf3ce44SJohn Forte icp->conn_params.header_digest =
1476fcf3ce44SJohn Forte ISCSI_DIGEST_CRC32C;
1477fcf3ce44SJohn Forte } else {
1478fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi "
1479fcf3ce44SJohn Forte "connection(%u) login "
1480fcf3ce44SJohn Forte "failed - HeaderDigest="
1481fcf3ce44SJohn Forte "None is required, can't "
1482fcf3ce44SJohn Forte "accept %s",
1483fcf3ce44SJohn Forte icp->conn_oid, text);
1484fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1485fcf3ce44SJohn Forte }
1486fcf3ce44SJohn Forte } else {
1487fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1488fcf3ce44SJohn Forte "login failed - HeaderDigest "
1489fcf3ce44SJohn Forte "can't accept %s", icp->conn_oid,
1490fcf3ce44SJohn Forte text);
1491fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1492fcf3ce44SJohn Forte }
1493fcf3ce44SJohn Forte text = value_end;
1494fcf3ce44SJohn Forte } else if (iscsi_find_key_value("DataDigest", text,
1495fcf3ce44SJohn Forte end, &value, &value_end)) {
1496fcf3ce44SJohn Forte
1497fcf3ce44SJohn Forte if (strcmp(value, "None") == 0) {
1498fcf3ce44SJohn Forte if (icp->conn_params.data_digest !=
1499fcf3ce44SJohn Forte ISCSI_DIGEST_CRC32C) {
1500fcf3ce44SJohn Forte icp->conn_params.data_digest =
1501fcf3ce44SJohn Forte ISCSI_DIGEST_NONE;
1502fcf3ce44SJohn Forte } else {
1503fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi "
1504fcf3ce44SJohn Forte "connection(%u) login "
1505fcf3ce44SJohn Forte "failed - DataDigest="
1506fcf3ce44SJohn Forte "CRC32C is required, "
1507fcf3ce44SJohn Forte "can't accept %s",
1508fcf3ce44SJohn Forte icp->conn_oid, text);
1509fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1510fcf3ce44SJohn Forte }
1511fcf3ce44SJohn Forte } else if (strcmp(value, "CRC32C") == 0) {
1512fcf3ce44SJohn Forte if (icp->conn_params.data_digest !=
1513fcf3ce44SJohn Forte ISCSI_DIGEST_NONE) {
1514fcf3ce44SJohn Forte icp->conn_params.data_digest =
1515fcf3ce44SJohn Forte ISCSI_DIGEST_CRC32C;
1516fcf3ce44SJohn Forte } else {
1517fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi "
1518fcf3ce44SJohn Forte "connection(%u) login "
1519fcf3ce44SJohn Forte "failed - DataDigest=None "
1520fcf3ce44SJohn Forte "is required, can't "
1521fcf3ce44SJohn Forte "accept %s",
1522fcf3ce44SJohn Forte icp->conn_oid, text);
1523fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1524fcf3ce44SJohn Forte }
1525fcf3ce44SJohn Forte } else {
1526fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1527fcf3ce44SJohn Forte "login failed - can't accept %s",
1528fcf3ce44SJohn Forte icp->conn_oid, text);
1529fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1530fcf3ce44SJohn Forte }
1531fcf3ce44SJohn Forte text = value_end;
1532fcf3ce44SJohn Forte
1533fcf3ce44SJohn Forte } else if (iscsi_find_key_value("DefaultTime2Wait",
1534fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1535fcf3ce44SJohn Forte
1536fcf3ce44SJohn Forte if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1537fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1538fcf3ce44SJohn Forte "login failed - DefaultTime2Wait "
1539fcf3ce44SJohn Forte "is invalid - protocol error",
1540fcf3ce44SJohn Forte icp->conn_oid);
1541fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1542fcf3ce44SJohn Forte }
1543fcf3ce44SJohn Forte icp->conn_params.default_time_to_wait =
1544fcf3ce44SJohn Forte (int)tmp;
1545fcf3ce44SJohn Forte
1546fcf3ce44SJohn Forte text = value_end;
1547fcf3ce44SJohn Forte
1548fcf3ce44SJohn Forte } else if (iscsi_find_key_value("DefaultTime2Retain",
1549fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1550fcf3ce44SJohn Forte
1551fcf3ce44SJohn Forte if (ddi_strtoul(value, &tmpe, 0, &tmp) != 0) {
1552fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1553fcf3ce44SJohn Forte "login failed - DefaultTime2Retain "
1554fcf3ce44SJohn Forte "is invalid - protocol error",
1555fcf3ce44SJohn Forte icp->conn_oid);
1556fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1557fcf3ce44SJohn Forte }
1558fcf3ce44SJohn Forte icp->conn_params.default_time_to_retain =
1559fcf3ce44SJohn Forte (int)tmp;
1560fcf3ce44SJohn Forte
1561fcf3ce44SJohn Forte text = value_end;
1562fcf3ce44SJohn Forte
1563fcf3ce44SJohn Forte } else if (iscsi_find_key_value("OFMarker", text,
1564fcf3ce44SJohn Forte end, &value, &value_end)) {
1565fcf3ce44SJohn Forte
1566fcf3ce44SJohn Forte /*
1567fcf3ce44SJohn Forte * result function is AND, target must
1568fcf3ce44SJohn Forte * honor our No
1569fcf3ce44SJohn Forte */
1570fcf3ce44SJohn Forte text = value_end;
1571fcf3ce44SJohn Forte
1572fcf3ce44SJohn Forte } else if (iscsi_find_key_value("OFMarkInt", text,
1573fcf3ce44SJohn Forte end, &value, &value_end)) {
1574fcf3ce44SJohn Forte
1575fcf3ce44SJohn Forte /*
1576fcf3ce44SJohn Forte * we don't do markers, so we don't care
1577fcf3ce44SJohn Forte */
1578fcf3ce44SJohn Forte text = value_end;
1579fcf3ce44SJohn Forte
1580fcf3ce44SJohn Forte } else if (iscsi_find_key_value("IFMarker", text,
1581fcf3ce44SJohn Forte end, &value, &value_end)) {
1582fcf3ce44SJohn Forte
1583fcf3ce44SJohn Forte /*
1584fcf3ce44SJohn Forte * result function is AND, target must
1585fcf3ce44SJohn Forte * honor our No
1586fcf3ce44SJohn Forte */
1587fcf3ce44SJohn Forte text = value_end;
1588fcf3ce44SJohn Forte
1589fcf3ce44SJohn Forte } else if (iscsi_find_key_value("IFMarkInt", text,
1590fcf3ce44SJohn Forte end, &value, &value_end)) {
1591fcf3ce44SJohn Forte
1592fcf3ce44SJohn Forte /*
1593fcf3ce44SJohn Forte * we don't do markers, so we don't care
1594fcf3ce44SJohn Forte */
1595fcf3ce44SJohn Forte text = value_end;
1596fcf3ce44SJohn Forte
1597fcf3ce44SJohn Forte } else if (iscsi_find_key_value("DataPDUInOrder",
1598fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1599fcf3ce44SJohn Forte
1600fcf3ce44SJohn Forte /*
1601fcf3ce44SJohn Forte * iSCSI RFC section 12.18 states that
1602fcf3ce44SJohn Forte * DataPDUInOrder is Irrelevant for a
1603fcf3ce44SJohn Forte * discovery session.
1604fcf3ce44SJohn Forte */
1605fcf3ce44SJohn Forte if (isp->sess_type ==
1606fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1607fcf3ce44SJohn Forte /* EMPTY */
1608fcf3ce44SJohn Forte } else if (value == NULL) {
1609fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1610fcf3ce44SJohn Forte "login failed - InitialR2T is "
1611fcf3ce44SJohn Forte "invalid - protocol error",
1612fcf3ce44SJohn Forte icp->conn_oid);
1613fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1614fcf3ce44SJohn Forte } else if (strcmp(value, "Yes") == 0) {
1615fcf3ce44SJohn Forte icp->conn_params.data_pdu_in_order =
1616fcf3ce44SJohn Forte B_TRUE;
1617fcf3ce44SJohn Forte } else if (strcmp(value, "No") == 0) {
1618fcf3ce44SJohn Forte icp->conn_params.data_pdu_in_order =
1619fcf3ce44SJohn Forte B_FALSE;
1620fcf3ce44SJohn Forte } else {
1621fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1622fcf3ce44SJohn Forte "login failed - InitialR2T is "
1623fcf3ce44SJohn Forte "invalid - protocol error",
1624fcf3ce44SJohn Forte icp->conn_oid);
1625fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1626fcf3ce44SJohn Forte }
1627fcf3ce44SJohn Forte text = value_end;
1628fcf3ce44SJohn Forte
1629fcf3ce44SJohn Forte } else if (iscsi_find_key_value("DataSequenceInOrder",
1630fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1631fcf3ce44SJohn Forte
1632fcf3ce44SJohn Forte /*
1633fcf3ce44SJohn Forte * iSCSI RFC section 12.19 states that
1634fcf3ce44SJohn Forte * DataSequenceInOrder is Irrelevant for a
1635fcf3ce44SJohn Forte * discovery session.
1636fcf3ce44SJohn Forte */
1637fcf3ce44SJohn Forte if (isp->sess_type ==
1638fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1639fcf3ce44SJohn Forte /* EMPTY */
1640fcf3ce44SJohn Forte } else if (value == NULL) {
1641fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1642fcf3ce44SJohn Forte "login failed - InitialR2T is "
1643fcf3ce44SJohn Forte "invalid - protocol error",
1644fcf3ce44SJohn Forte icp->conn_oid);
1645fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1646fcf3ce44SJohn Forte } else if (strcmp(value, "Yes") == 0) {
1647fcf3ce44SJohn Forte icp->conn_params.
1648fcf3ce44SJohn Forte data_sequence_in_order = B_TRUE;
1649fcf3ce44SJohn Forte } else if (strcmp(value, "No") == 0) {
1650fcf3ce44SJohn Forte icp->conn_params.
1651fcf3ce44SJohn Forte data_sequence_in_order = B_FALSE;
1652fcf3ce44SJohn Forte } else {
1653fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1654fcf3ce44SJohn Forte "login failed - InitialR2T is "
1655fcf3ce44SJohn Forte "invalid - protocol error",
1656fcf3ce44SJohn Forte icp->conn_oid);
1657fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1658fcf3ce44SJohn Forte }
1659fcf3ce44SJohn Forte text = value_end;
1660fcf3ce44SJohn Forte
1661fcf3ce44SJohn Forte } else if (iscsi_find_key_value("MaxOutstandingR2T",
1662fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1663fcf3ce44SJohn Forte
1664fcf3ce44SJohn Forte /*
1665fcf3ce44SJohn Forte * iSCSI RFC section 12.17 states that
1666fcf3ce44SJohn Forte * MaxOutstandingR2T is Irrelevant for a
1667fcf3ce44SJohn Forte * discovery session.
1668fcf3ce44SJohn Forte */
1669fcf3ce44SJohn Forte if (isp->sess_type ==
1670fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1671fcf3ce44SJohn Forte /* EMPTY */
1672fcf3ce44SJohn Forte } else if (strcmp(value, "1")) {
1673fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1674fcf3ce44SJohn Forte "login failed - can't accept "
1675fcf3ce44SJohn Forte "MaxOutstandingR2T %s",
1676fcf3ce44SJohn Forte icp->conn_oid, value);
1677fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1678fcf3ce44SJohn Forte }
1679fcf3ce44SJohn Forte text = value_end;
1680fcf3ce44SJohn Forte
1681fcf3ce44SJohn Forte } else if (iscsi_find_key_value("MaxConnections",
1682fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1683fcf3ce44SJohn Forte
1684fcf3ce44SJohn Forte /*
1685fcf3ce44SJohn Forte * iSCSI RFC section 12.2 states that
1686fcf3ce44SJohn Forte * MaxConnections is Irrelevant for a
1687fcf3ce44SJohn Forte * discovery session.
1688fcf3ce44SJohn Forte */
1689fcf3ce44SJohn Forte if (isp->sess_type ==
1690fcf3ce44SJohn Forte ISCSI_SESS_TYPE_DISCOVERY) {
1691fcf3ce44SJohn Forte /* EMPTY */
1692fcf3ce44SJohn Forte } else if (strcmp(value, "1")) {
1693fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1694fcf3ce44SJohn Forte "login failed - can't accept "
1695fcf3ce44SJohn Forte "MaxConnections %s",
1696fcf3ce44SJohn Forte icp->conn_oid, value);
1697fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1698fcf3ce44SJohn Forte }
1699fcf3ce44SJohn Forte text = value_end;
1700fcf3ce44SJohn Forte
1701fcf3ce44SJohn Forte } else if (iscsi_find_key_value("ErrorRecoveryLevel",
1702fcf3ce44SJohn Forte text, end, &value, &value_end)) {
1703fcf3ce44SJohn Forte
1704fcf3ce44SJohn Forte if (strcmp(value, "0")) {
1705fcf3ce44SJohn Forte
1706fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1707fcf3ce44SJohn Forte "login failed - can't accept "
1708fcf3ce44SJohn Forte "ErrorRecoveryLevel %s",
1709fcf3ce44SJohn Forte icp->conn_oid, value);
1710fcf3ce44SJohn Forte return (ISCSI_STATUS_NEGO_FAIL);
1711fcf3ce44SJohn Forte }
1712fcf3ce44SJohn Forte text = value_end;
1713fcf3ce44SJohn Forte
1714fcf3ce44SJohn Forte } else {
1715fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) "
1716fcf3ce44SJohn Forte "login failed - ignoring login "
1717fcf3ce44SJohn Forte "parameter %s", icp->conn_oid, value);
1718fcf3ce44SJohn Forte text = value_end;
1719fcf3ce44SJohn Forte }
1720fcf3ce44SJohn Forte break;
1721fcf3ce44SJohn Forte default:
1722fcf3ce44SJohn Forte return (ISCSI_STATUS_INTERNAL_ERROR);
1723fcf3ce44SJohn Forte }
1724fcf3ce44SJohn Forte }
1725fcf3ce44SJohn Forte
1726fcf3ce44SJohn Forte /*
1727fcf3ce44SJohn Forte * iSCSI RFC section 12.14 states that
1728fcf3ce44SJohn Forte * FirstBurstLength is Irrelevant if
1729fcf3ce44SJohn Forte * InitialR2T=Yes and ImmediateData=No.
1730fcf3ce44SJohn Forte * This is a final check to make sure
1731fcf3ce44SJohn Forte * the array didn't make a protocol
1732fcf3ce44SJohn Forte * violation.
1733fcf3ce44SJohn Forte */
1734fcf3ce44SJohn Forte if ((fbl_irrelevant == B_TRUE) &&
1735fcf3ce44SJohn Forte ((icp->conn_params.initial_r2t != B_TRUE) ||
1736fcf3ce44SJohn Forte (icp->conn_params.immediate_data != B_FALSE))) {
1737fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login failed - "
1738fcf3ce44SJohn Forte "FirstBurstLength=Irrelevant and (InitialR2T!=Yes or "
1739fcf3ce44SJohn Forte "ImmediateData!=No) - protocol error", icp->conn_oid);
1740fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1741fcf3ce44SJohn Forte }
1742fcf3ce44SJohn Forte
1743fcf3ce44SJohn Forte if (icp->conn_current_stage == ISCSI_SECURITY_NEGOTIATION_STAGE) {
1744fcf3ce44SJohn Forte switch (iscsiAuthClientRecvEnd(auth_client, iscsi_null_callback,
1745fcf3ce44SJohn Forte (void *)isp, NULL)) {
1746fcf3ce44SJohn Forte case iscsiAuthStatusContinue:
1747fcf3ce44SJohn Forte /*
1748fcf3ce44SJohn Forte * continue sending PDUs
1749fcf3ce44SJohn Forte */
1750fcf3ce44SJohn Forte break;
1751fcf3ce44SJohn Forte
1752fcf3ce44SJohn Forte case iscsiAuthStatusPass:
1753fcf3ce44SJohn Forte break;
1754fcf3ce44SJohn Forte
1755fcf3ce44SJohn Forte case iscsiAuthStatusInProgress:
1756fcf3ce44SJohn Forte /*
1757fcf3ce44SJohn Forte * this should only occur if we were authenticating the
1758fcf3ce44SJohn Forte * target, which we don't do yet, so treat this as an
1759fcf3ce44SJohn Forte * error.
1760fcf3ce44SJohn Forte */
1761fcf3ce44SJohn Forte case iscsiAuthStatusNoError:
1762fcf3ce44SJohn Forte /*
1763fcf3ce44SJohn Forte * treat this as an error, since we should get a
1764fcf3ce44SJohn Forte * different code
1765fcf3ce44SJohn Forte */
1766fcf3ce44SJohn Forte case iscsiAuthStatusError:
1767fcf3ce44SJohn Forte case iscsiAuthStatusFail:
1768fcf3ce44SJohn Forte default:
1769fcf3ce44SJohn Forte debug_status = 0;
1770fcf3ce44SJohn Forte
1771fcf3ce44SJohn Forte if (iscsiAuthClientGetDebugStatus(auth_client,
1772fcf3ce44SJohn Forte &debug_status) != iscsiAuthStatusNoError) {
1773fcf3ce44SJohn Forte
1774fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1775fcf3ce44SJohn Forte "failed - authentication failed with "
1776fcf3ce44SJohn Forte "target (%s)", icp->conn_oid,
1777fcf3ce44SJohn Forte iscsiAuthClientDebugStatusToText(
1778fcf3ce44SJohn Forte debug_status));
1779fcf3ce44SJohn Forte
1780fcf3ce44SJohn Forte } else {
1781fcf3ce44SJohn Forte
1782fcf3ce44SJohn Forte cmn_err(CE_WARN, "iscsi connection(%u) login "
1783fcf3ce44SJohn Forte "failed - authentication failed with "
1784fcf3ce44SJohn Forte "target", icp->conn_oid);
1785fcf3ce44SJohn Forte
1786fcf3ce44SJohn Forte }
1787fcf3ce44SJohn Forte return (ISCSI_STATUS_AUTHENTICATION_FAILED);
1788fcf3ce44SJohn Forte }
1789fcf3ce44SJohn Forte }
1790fcf3ce44SJohn Forte
1791fcf3ce44SJohn Forte /*
1792fcf3ce44SJohn Forte * record some of the PDU fields for later use
1793fcf3ce44SJohn Forte */
1794fcf3ce44SJohn Forte isp->sess_tsid = ntohs(ilrhp->tsid);
1795fcf3ce44SJohn Forte isp->sess_expcmdsn = ntohl(ilrhp->expcmdsn);
1796fcf3ce44SJohn Forte isp->sess_maxcmdsn = ntohl(ilrhp->maxcmdsn);
1797fcf3ce44SJohn Forte if (ilrhp->status_class == ISCSI_STATUS_CLASS_SUCCESS) {
1798fcf3ce44SJohn Forte icp->conn_expstatsn = ntohl(ilrhp->statsn) + 1;
1799fcf3ce44SJohn Forte }
1800fcf3ce44SJohn Forte
1801fcf3ce44SJohn Forte if (transit) {
1802fcf3ce44SJohn Forte /*
1803fcf3ce44SJohn Forte * advance to the next stage
1804fcf3ce44SJohn Forte */
1805fcf3ce44SJohn Forte icp->conn_partial_response = 0;
1806fcf3ce44SJohn Forte icp->conn_current_stage =
1807fcf3ce44SJohn Forte ilrhp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
1808fcf3ce44SJohn Forte } else {
1809fcf3ce44SJohn Forte /*
1810fcf3ce44SJohn Forte * we got a partial response, don't advance, more
1811fcf3ce44SJohn Forte * negotiation to do
1812fcf3ce44SJohn Forte */
1813fcf3ce44SJohn Forte icp->conn_partial_response = 1;
1814fcf3ce44SJohn Forte }
1815fcf3ce44SJohn Forte
1816fcf3ce44SJohn Forte /*
1817fcf3ce44SJohn Forte * this PDU is ok, though the login process
1818fcf3ce44SJohn Forte * may not be done yet
1819fcf3ce44SJohn Forte */
1820fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
1821fcf3ce44SJohn Forte }
1822fcf3ce44SJohn Forte
1823fcf3ce44SJohn Forte /*
1824fcf3ce44SJohn Forte * iscsi_add_text - caller is assumed to be well-behaved and passing NUL
1825fcf3ce44SJohn Forte * terminated strings
1826fcf3ce44SJohn Forte */
1827fcf3ce44SJohn Forte int
iscsi_add_text(idm_pdu_t * text_pdu,int max_data_length,char * param,char * value)182830e7468fSPeter Dunlap iscsi_add_text(idm_pdu_t *text_pdu, int max_data_length,
1829fcf3ce44SJohn Forte char *param, char *value)
1830fcf3ce44SJohn Forte {
1831fcf3ce44SJohn Forte int param_len = 0;
1832fcf3ce44SJohn Forte int value_len = 0;
1833fcf3ce44SJohn Forte int length = 0;
1834fcf3ce44SJohn Forte int pdu_length = 0;
1835fcf3ce44SJohn Forte char *text = NULL;
1836fcf3ce44SJohn Forte char *end = NULL;
1837fcf3ce44SJohn Forte
183830e7468fSPeter Dunlap ASSERT(text_pdu != NULL);
1839fcf3ce44SJohn Forte ASSERT(param != NULL);
1840fcf3ce44SJohn Forte ASSERT(value != NULL);
1841fcf3ce44SJohn Forte
1842fcf3ce44SJohn Forte param_len = strlen(param);
1843fcf3ce44SJohn Forte value_len = strlen(value);
1844fcf3ce44SJohn Forte /* param, separator, value, and trailing NULL */
1845fcf3ce44SJohn Forte length = param_len + 1 + value_len + 1;
184630e7468fSPeter Dunlap pdu_length = text_pdu->isp_datalen;
184730e7468fSPeter Dunlap text = (char *)text_pdu->isp_data + pdu_length;
184830e7468fSPeter Dunlap end = (char *)text_pdu->isp_data + max_data_length;
1849fcf3ce44SJohn Forte pdu_length += length;
1850fcf3ce44SJohn Forte
1851fcf3ce44SJohn Forte if (text + length >= end) {
1852fcf3ce44SJohn Forte return (0);
1853fcf3ce44SJohn Forte }
1854fcf3ce44SJohn Forte
1855fcf3ce44SJohn Forte /* param */
1856fcf3ce44SJohn Forte (void) strncpy(text, param, param_len);
1857fcf3ce44SJohn Forte text += param_len;
1858fcf3ce44SJohn Forte
1859fcf3ce44SJohn Forte /* separator */
1860fcf3ce44SJohn Forte *text++ = ISCSI_TEXT_SEPARATOR;
1861fcf3ce44SJohn Forte
1862fcf3ce44SJohn Forte /* value */
1863fcf3ce44SJohn Forte (void) strncpy(text, value, value_len);
1864fcf3ce44SJohn Forte text += value_len;
1865fcf3ce44SJohn Forte
1866fcf3ce44SJohn Forte /* NULL */
1867fcf3ce44SJohn Forte *text++ = '\0';
1868fcf3ce44SJohn Forte
1869fcf3ce44SJohn Forte /* update the length in the PDU header */
187030e7468fSPeter Dunlap text_pdu->isp_datalen = pdu_length;
187130e7468fSPeter Dunlap hton24(text_pdu->isp_hdr->dlength, pdu_length);
1872fcf3ce44SJohn Forte
1873fcf3ce44SJohn Forte return (1);
1874fcf3ce44SJohn Forte }
1875fcf3ce44SJohn Forte
1876fcf3ce44SJohn Forte /*
1877fcf3ce44SJohn Forte * iscsi_get_next_text - get the next line of text from the given data
1878fcf3ce44SJohn Forte * buffer. This function searches from the address given for the
1879fcf3ce44SJohn Forte * curr_text parameter. If curr_text_parameter is NULL return first
1880fcf3ce44SJohn Forte * line in buffer. The return value is the address of the next line
1881fcf3ce44SJohn Forte * based upon where curr_text is located.
1882fcf3ce44SJohn Forte *
1883fcf3ce44SJohn Forte */
1884fcf3ce44SJohn Forte char *
iscsi_get_next_text(char * data,int max_data_length,char * curr_text)1885fcf3ce44SJohn Forte iscsi_get_next_text(char *data, int max_data_length, char *curr_text)
1886fcf3ce44SJohn Forte {
1887fcf3ce44SJohn Forte char *curr_data;
1888fcf3ce44SJohn Forte
1889fcf3ce44SJohn Forte ASSERT(data != NULL);
1890fcf3ce44SJohn Forte
1891fcf3ce44SJohn Forte /* check if any data exists, if not return */
1892fcf3ce44SJohn Forte if (max_data_length == 0) {
1893fcf3ce44SJohn Forte return (NULL);
1894fcf3ce44SJohn Forte }
1895fcf3ce44SJohn Forte
1896fcf3ce44SJohn Forte /* handle first call to this function */
1897fcf3ce44SJohn Forte if (curr_text == NULL) {
1898fcf3ce44SJohn Forte return (data);
1899fcf3ce44SJohn Forte }
1900fcf3ce44SJohn Forte
1901fcf3ce44SJohn Forte /* move to next text string */
1902fcf3ce44SJohn Forte curr_data = curr_text;
1903fcf3ce44SJohn Forte while ((curr_data < (data + max_data_length)) && *curr_data) {
1904fcf3ce44SJohn Forte curr_data++;
1905fcf3ce44SJohn Forte }
1906fcf3ce44SJohn Forte curr_data++; /* go past the NULL to the next entry */
1907fcf3ce44SJohn Forte
1908fcf3ce44SJohn Forte /* check whether data end reached */
1909fcf3ce44SJohn Forte if (curr_data >= (data + max_data_length)) {
1910fcf3ce44SJohn Forte return (NULL);
1911fcf3ce44SJohn Forte }
1912fcf3ce44SJohn Forte
1913fcf3ce44SJohn Forte return (curr_data);
1914fcf3ce44SJohn Forte }
1915fcf3ce44SJohn Forte
1916fcf3ce44SJohn Forte
1917fcf3ce44SJohn Forte /*
1918fcf3ce44SJohn Forte * iscsi_find_key_value -
1919fcf3ce44SJohn Forte *
1920fcf3ce44SJohn Forte */
1921fcf3ce44SJohn Forte static int
iscsi_find_key_value(char * param,char * ihp,char * pdu_end,char ** value_start,char ** value_end)1922fcf3ce44SJohn Forte iscsi_find_key_value(char *param, char *ihp, char *pdu_end,
1923fcf3ce44SJohn Forte char **value_start, char **value_end)
1924fcf3ce44SJohn Forte {
1925fcf3ce44SJohn Forte char *str = param;
1926fcf3ce44SJohn Forte char *text = ihp;
1927fcf3ce44SJohn Forte char *value = NULL;
1928fcf3ce44SJohn Forte
1929fcf3ce44SJohn Forte if (value_start)
1930fcf3ce44SJohn Forte *value_start = NULL;
1931fcf3ce44SJohn Forte if (value_end)
1932fcf3ce44SJohn Forte *value_end = NULL;
1933fcf3ce44SJohn Forte
1934fcf3ce44SJohn Forte /*
1935fcf3ce44SJohn Forte * make sure they contain the same bytes
1936fcf3ce44SJohn Forte */
1937fcf3ce44SJohn Forte while (*str) {
1938fcf3ce44SJohn Forte if (text >= pdu_end) {
1939fcf3ce44SJohn Forte return (0);
1940fcf3ce44SJohn Forte }
1941fcf3ce44SJohn Forte if (*text == '\0') {
1942fcf3ce44SJohn Forte return (0);
1943fcf3ce44SJohn Forte }
1944fcf3ce44SJohn Forte if (*str != *text) {
1945fcf3ce44SJohn Forte return (0);
1946fcf3ce44SJohn Forte }
1947fcf3ce44SJohn Forte str++;
1948fcf3ce44SJohn Forte text++;
1949fcf3ce44SJohn Forte }
1950fcf3ce44SJohn Forte
1951fcf3ce44SJohn Forte if ((text >= pdu_end) ||
1952fcf3ce44SJohn Forte (*text == '\0') ||
1953fcf3ce44SJohn Forte (*text != ISCSI_TEXT_SEPARATOR)) {
1954fcf3ce44SJohn Forte return (0);
1955fcf3ce44SJohn Forte }
1956fcf3ce44SJohn Forte
1957fcf3ce44SJohn Forte /*
1958fcf3ce44SJohn Forte * find the value
1959fcf3ce44SJohn Forte */
1960fcf3ce44SJohn Forte value = text + 1;
1961fcf3ce44SJohn Forte
1962fcf3ce44SJohn Forte /*
1963fcf3ce44SJohn Forte * find the end of the value
1964fcf3ce44SJohn Forte */
1965fcf3ce44SJohn Forte while ((text < pdu_end) && (*text))
1966fcf3ce44SJohn Forte text++;
1967fcf3ce44SJohn Forte
1968fcf3ce44SJohn Forte if (value_start)
1969fcf3ce44SJohn Forte *value_start = value;
1970fcf3ce44SJohn Forte if (value_end)
1971fcf3ce44SJohn Forte *value_end = text;
1972fcf3ce44SJohn Forte
1973fcf3ce44SJohn Forte return (1);
1974fcf3ce44SJohn Forte }
1975fcf3ce44SJohn Forte
1976fcf3ce44SJohn Forte
1977fcf3ce44SJohn Forte /*
1978fcf3ce44SJohn Forte * iscsi_update_address - This function is used on a login redirection.
1979fcf3ce44SJohn Forte * During the login redirection we are asked to switch to an IP address
1980fcf3ce44SJohn Forte * port different than the one we were logging into.
1981fcf3ce44SJohn Forte */
1982fcf3ce44SJohn Forte static iscsi_status_t
iscsi_update_address(iscsi_conn_t * icp,char * in)1983fcf3ce44SJohn Forte iscsi_update_address(iscsi_conn_t *icp, char *in)
1984fcf3ce44SJohn Forte {
1985fcf3ce44SJohn Forte char *addr_str, *port_str, *tpgt_str;
1986fcf3ce44SJohn Forte int type;
1987fcf3ce44SJohn Forte struct hostent *hptr;
1988fcf3ce44SJohn Forte unsigned long tmp;
1989fcf3ce44SJohn Forte int error_num;
1990fcf3ce44SJohn Forte int port;
1991fcf3ce44SJohn Forte
1992fcf3ce44SJohn Forte ASSERT(icp != NULL);
1993fcf3ce44SJohn Forte ASSERT(in != NULL);
1994fcf3ce44SJohn Forte
1995fcf3ce44SJohn Forte /* parse login redirection response */
1996fcf3ce44SJohn Forte if (parse_addr_port_tpgt(in, &addr_str, &type,
1997fcf3ce44SJohn Forte &port_str, &tpgt_str) == B_FALSE) {
1998fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
1999fcf3ce44SJohn Forte }
2000fcf3ce44SJohn Forte
2001fcf3ce44SJohn Forte /* convert addr_str */
2002fcf3ce44SJohn Forte hptr = kgetipnodebyname(addr_str, type, AI_ALL, &error_num);
2003fcf3ce44SJohn Forte if (!hptr) {
2004fcf3ce44SJohn Forte return (ISCSI_STATUS_PROTOCOL_ERROR);
2005fcf3ce44SJohn Forte }
2006fcf3ce44SJohn Forte
2007fcf3ce44SJohn Forte /* convert port_str */
2008fcf3ce44SJohn Forte if (port_str != NULL) {
2009fcf3ce44SJohn Forte (void) ddi_strtoul(port_str, NULL, 0, &tmp);
2010fcf3ce44SJohn Forte port = (int)tmp;
2011fcf3ce44SJohn Forte } else {
2012fcf3ce44SJohn Forte port = ISCSI_LISTEN_PORT;
2013fcf3ce44SJohn Forte }
2014fcf3ce44SJohn Forte
2015fcf3ce44SJohn Forte iscsid_addr_to_sockaddr(hptr->h_length, *hptr->h_addr_list,
2016fcf3ce44SJohn Forte port, &icp->conn_curr_addr.sin);
2017fcf3ce44SJohn Forte
2018fcf3ce44SJohn Forte kfreehostent(hptr);
2019fcf3ce44SJohn Forte return (ISCSI_STATUS_SUCCESS);
2020fcf3ce44SJohn Forte }
2021fcf3ce44SJohn Forte
202230e7468fSPeter Dunlap void
iscsi_login_update_state(iscsi_conn_t * icp,iscsi_login_state_t next_state)202330e7468fSPeter Dunlap iscsi_login_update_state(iscsi_conn_t *icp, iscsi_login_state_t next_state)
202430e7468fSPeter Dunlap {
202530e7468fSPeter Dunlap mutex_enter(&icp->conn_login_mutex);
202630e7468fSPeter Dunlap (void) iscsi_login_update_state_locked(icp, next_state);
202730e7468fSPeter Dunlap mutex_exit(&icp->conn_login_mutex);
202830e7468fSPeter Dunlap }
202930e7468fSPeter Dunlap
203030e7468fSPeter Dunlap void
iscsi_login_update_state_locked(iscsi_conn_t * icp,iscsi_login_state_t next_state)203130e7468fSPeter Dunlap iscsi_login_update_state_locked(iscsi_conn_t *icp,
203230e7468fSPeter Dunlap iscsi_login_state_t next_state)
203330e7468fSPeter Dunlap {
203430e7468fSPeter Dunlap ASSERT(mutex_owned(&icp->conn_login_mutex));
203530e7468fSPeter Dunlap next_state = (next_state > LOGIN_MAX) ? LOGIN_MAX : next_state;
203630e7468fSPeter Dunlap idm_sm_audit_state_change(&icp->conn_state_audit,
203730e7468fSPeter Dunlap SAS_ISCSI_LOGIN, icp->conn_login_state, next_state);
203830e7468fSPeter Dunlap
203930e7468fSPeter Dunlap ISCSI_LOGIN_LOG(CE_NOTE, "iscsi_login_update_state conn %p %d -> %d",
204030e7468fSPeter Dunlap (void *)icp, icp->conn_login_state, next_state);
204130e7468fSPeter Dunlap
204230e7468fSPeter Dunlap icp->conn_login_state = next_state;
204330e7468fSPeter Dunlap cv_broadcast(&icp->conn_login_cv);
204430e7468fSPeter Dunlap }
204530e7468fSPeter Dunlap
204630e7468fSPeter Dunlap
2047fcf3ce44SJohn Forte
2048fcf3ce44SJohn Forte /*
2049fcf3ce44SJohn Forte * iscsi_null_callback - This callback may be used under certain
2050fcf3ce44SJohn Forte * conditions when authenticating a target, but I'm not sure what
2051fcf3ce44SJohn Forte * we need to do here.
2052fcf3ce44SJohn Forte */
2053fcf3ce44SJohn Forte /* ARGSUSED */
2054fcf3ce44SJohn Forte static void
iscsi_null_callback(void * user_handle,void * message_handle,int auth_status)2055fcf3ce44SJohn Forte iscsi_null_callback(void *user_handle, void *message_handle, int auth_status)
2056fcf3ce44SJohn Forte {
2057fcf3ce44SJohn Forte }
2058fcf3ce44SJohn Forte
2059fcf3ce44SJohn Forte
2060fcf3ce44SJohn Forte /*
2061fcf3ce44SJohn Forte * iscsi_login_failure_str -
2062fcf3ce44SJohn Forte *
2063fcf3ce44SJohn Forte */
2064fcf3ce44SJohn Forte static char *
iscsi_login_failure_str(uchar_t status_class,uchar_t status_detail)2065fcf3ce44SJohn Forte iscsi_login_failure_str(uchar_t status_class, uchar_t status_detail)
2066fcf3ce44SJohn Forte {
2067fcf3ce44SJohn Forte switch (status_class) {
2068fcf3ce44SJohn Forte case 0x00:
2069fcf3ce44SJohn Forte switch (status_detail) {
2070fcf3ce44SJohn Forte case 0x00:
2071fcf3ce44SJohn Forte return ("Login is proceeding okay.");
2072fcf3ce44SJohn Forte default:
2073fcf3ce44SJohn Forte break;
2074fcf3ce44SJohn Forte }
20757c9ce9e0SToomas Soome break;
2076fcf3ce44SJohn Forte case 0x01:
2077fcf3ce44SJohn Forte switch (status_detail) {
2078fcf3ce44SJohn Forte case 0x01:
2079fcf3ce44SJohn Forte return ("Requested ITN has moved temporarily to "
2080fcf3ce44SJohn Forte "the address provided.");
2081fcf3ce44SJohn Forte case 0x02:
2082fcf3ce44SJohn Forte return ("Requested ITN has moved permanently to "
2083fcf3ce44SJohn Forte "the address provided.");
2084fcf3ce44SJohn Forte default:
2085fcf3ce44SJohn Forte break;
2086fcf3ce44SJohn Forte }
20877c9ce9e0SToomas Soome break;
2088fcf3ce44SJohn Forte case 0x02:
2089fcf3ce44SJohn Forte switch (status_detail) {
2090fcf3ce44SJohn Forte case 0x00:
2091fcf3ce44SJohn Forte return ("Miscellaneous iSCSI initiator errors.");
2092fcf3ce44SJohn Forte case 0x01:
2093fcf3ce44SJohn Forte return ("Initiator could not be successfully "
2094fcf3ce44SJohn Forte "authenticated.");
2095fcf3ce44SJohn Forte case 0x02:
2096fcf3ce44SJohn Forte return ("Initiator is not allowed access to the "
2097fcf3ce44SJohn Forte "given target.");
2098fcf3ce44SJohn Forte case 0x03:
2099fcf3ce44SJohn Forte return ("Requested ITN does not exist at this "
2100fcf3ce44SJohn Forte "address.");
2101fcf3ce44SJohn Forte case 0x04:
2102fcf3ce44SJohn Forte return ("Requested ITN has been removed and no "
2103fcf3ce44SJohn Forte "forwarding address is provided.");
2104fcf3ce44SJohn Forte case 0x05:
2105fcf3ce44SJohn Forte return ("Requested iSCSI version range is not "
2106fcf3ce44SJohn Forte "supported by the target.");
2107fcf3ce44SJohn Forte case 0x06:
2108fcf3ce44SJohn Forte return ("No more connections can be accepted on "
2109fcf3ce44SJohn Forte "this Session ID (SSID).");
2110fcf3ce44SJohn Forte case 0x07:
2111fcf3ce44SJohn Forte return ("Missing parameters (e.g., iSCSI initiator "
2112fcf3ce44SJohn Forte "and/or target name).");
2113fcf3ce44SJohn Forte case 0x08:
2114fcf3ce44SJohn Forte return ("Target does not support session spanning "
2115fcf3ce44SJohn Forte "to this connection (address).");
2116fcf3ce44SJohn Forte case 0x09:
2117fcf3ce44SJohn Forte return ("Target does not support this type of "
2118fcf3ce44SJohn Forte "session or not from this initiator.");
2119fcf3ce44SJohn Forte case 0x0A:
2120fcf3ce44SJohn Forte return ("Attempt to add a connection to a "
2121fcf3ce44SJohn Forte "nonexistent session.");
2122fcf3ce44SJohn Forte case 0x0B:
2123fcf3ce44SJohn Forte return ("Invalid request type during login.");
2124fcf3ce44SJohn Forte default:
2125fcf3ce44SJohn Forte break;
2126fcf3ce44SJohn Forte }
21277c9ce9e0SToomas Soome break;
2128fcf3ce44SJohn Forte case 0x03:
2129fcf3ce44SJohn Forte switch (status_detail) {
2130fcf3ce44SJohn Forte case 0x00:
2131fcf3ce44SJohn Forte return ("Target hardware or software error.");
2132fcf3ce44SJohn Forte case 0x01:
2133fcf3ce44SJohn Forte return ("iSCSI service or target is not currently "
2134fcf3ce44SJohn Forte "operational.");
2135fcf3ce44SJohn Forte case 0x02:
2136fcf3ce44SJohn Forte return ("Target has insufficient session, connection "
2137fcf3ce44SJohn Forte "or other resources.");
2138fcf3ce44SJohn Forte default:
2139fcf3ce44SJohn Forte break;
2140fcf3ce44SJohn Forte }
21417c9ce9e0SToomas Soome break;
2142fcf3ce44SJohn Forte }
2143fcf3ce44SJohn Forte return ("Unknown login response received.");
2144fcf3ce44SJohn Forte }
2145fcf3ce44SJohn Forte
2146fcf3ce44SJohn Forte
2147fcf3ce44SJohn Forte /*
2148fcf3ce44SJohn Forte * iscsi_login_connect -
2149fcf3ce44SJohn Forte */
2150fcf3ce44SJohn Forte static iscsi_status_t
iscsi_login_connect(iscsi_conn_t * icp)2151fcf3ce44SJohn Forte iscsi_login_connect(iscsi_conn_t *icp)
2152fcf3ce44SJohn Forte {
2153fcf3ce44SJohn Forte iscsi_hba_t *ihp;
2154fcf3ce44SJohn Forte iscsi_sess_t *isp;
2155fcf3ce44SJohn Forte struct sockaddr *addr;
215630e7468fSPeter Dunlap idm_conn_req_t cr;
215730e7468fSPeter Dunlap idm_status_t rval;
2158d3d50737SRafael Vanoni clock_t lbolt;
2159fcf3ce44SJohn Forte
2160fcf3ce44SJohn Forte ASSERT(icp != NULL);
2161fcf3ce44SJohn Forte isp = icp->conn_sess;
2162fcf3ce44SJohn Forte ASSERT(isp != NULL);
2163fcf3ce44SJohn Forte ihp = isp->sess_hba;
2164fcf3ce44SJohn Forte ASSERT(ihp != NULL);
2165fcf3ce44SJohn Forte addr = &icp->conn_curr_addr.sin;
2166fcf3ce44SJohn Forte
2167fcf3ce44SJohn Forte /* Make sure that scope_id is zero if it is an IPv6 address */
2168fcf3ce44SJohn Forte if (addr->sa_family == AF_INET6) {
2169fcf3ce44SJohn Forte ((struct sockaddr_in6 *)addr)->sin6_scope_id = 0;
2170fcf3ce44SJohn Forte }
2171fcf3ce44SJohn Forte
217230e7468fSPeter Dunlap /* delay the connect process if required */
217330e7468fSPeter Dunlap lbolt = ddi_get_lbolt();
217430e7468fSPeter Dunlap if (lbolt < icp->conn_login_min) {
2175aff4bce5Syi zhang - Sun Microsystems - Beijing China if (icp->conn_login_max < icp->conn_login_min) {
2176aff4bce5Syi zhang - Sun Microsystems - Beijing China delay(icp->conn_login_max - lbolt);
2177aff4bce5Syi zhang - Sun Microsystems - Beijing China } else {
217830e7468fSPeter Dunlap delay(icp->conn_login_min - lbolt);
217930e7468fSPeter Dunlap }
2180aff4bce5Syi zhang - Sun Microsystems - Beijing China }
2181fcf3ce44SJohn Forte
218230e7468fSPeter Dunlap /* Create IDM connection context */
218330e7468fSPeter Dunlap cr.cr_domain = addr->sa_family;
218430e7468fSPeter Dunlap cr.cr_type = SOCK_STREAM;
218530e7468fSPeter Dunlap cr.cr_protocol = 0;
218630e7468fSPeter Dunlap cr.cr_bound = icp->conn_bound;
218730e7468fSPeter Dunlap cr.cr_li = icp->conn_sess->sess_hba->hba_li;
218830e7468fSPeter Dunlap cr.icr_conn_ops.icb_rx_misc = &iscsi_rx_misc_pdu;
218930e7468fSPeter Dunlap cr.icr_conn_ops.icb_rx_error = &iscsi_rx_error_pdu;
219030e7468fSPeter Dunlap cr.icr_conn_ops.icb_rx_scsi_rsp = &iscsi_rx_scsi_rsp;
219130e7468fSPeter Dunlap cr.icr_conn_ops.icb_client_notify = &iscsi_client_notify;
219230e7468fSPeter Dunlap cr.icr_conn_ops.icb_build_hdr = &iscsi_build_hdr;
219330e7468fSPeter Dunlap cr.icr_conn_ops.icb_task_aborted = &iscsi_task_aborted;
219430e7468fSPeter Dunlap bcopy(addr, &cr.cr_ini_dst_addr,
219530e7468fSPeter Dunlap sizeof (cr.cr_ini_dst_addr));
219630e7468fSPeter Dunlap bcopy(&icp->conn_bound_addr, &cr.cr_bound_addr,
219730e7468fSPeter Dunlap sizeof (cr.cr_bound_addr));
2198dedec472SJack Meng if (isp->sess_boot == B_TRUE) {
2199dedec472SJack Meng cr.cr_boot_conn = B_TRUE;
2200dedec472SJack Meng } else {
2201dedec472SJack Meng cr.cr_boot_conn = B_FALSE;
2202dedec472SJack Meng }
220330e7468fSPeter Dunlap
220430e7468fSPeter Dunlap /*
220530e7468fSPeter Dunlap * Allocate IDM connection context
220630e7468fSPeter Dunlap */
220730e7468fSPeter Dunlap rval = idm_ini_conn_create(&cr, &icp->conn_ic);
220830e7468fSPeter Dunlap if (rval != IDM_STATUS_SUCCESS) {
220930e7468fSPeter Dunlap return (ISCSI_STATUS_LOGIN_FAILED);
221030e7468fSPeter Dunlap }
221130e7468fSPeter Dunlap
221230e7468fSPeter Dunlap icp->conn_ic->ic_handle = icp;
221330e7468fSPeter Dunlap
221430e7468fSPeter Dunlap /*
221530e7468fSPeter Dunlap * About to initiate connect, reset login state.
221630e7468fSPeter Dunlap */
221730e7468fSPeter Dunlap iscsi_login_update_state(icp, LOGIN_START);
221830e7468fSPeter Dunlap
221930e7468fSPeter Dunlap /*
222030e7468fSPeter Dunlap * Make sure the connection doesn't go away until we are done with it.
222130e7468fSPeter Dunlap * This hold will prevent us from receiving a CN_CONNECT_DESTROY
222230e7468fSPeter Dunlap * notification on this connection until we are ready.
222330e7468fSPeter Dunlap */
222430e7468fSPeter Dunlap idm_conn_hold(icp->conn_ic);
222530e7468fSPeter Dunlap
222630e7468fSPeter Dunlap /*
2227aff4bce5Syi zhang - Sun Microsystems - Beijing China * When iSCSI initiator to target IO timeout or connection failure
2228aff4bce5Syi zhang - Sun Microsystems - Beijing China * Connection retry is needed for normal operational session.
2229aff4bce5Syi zhang - Sun Microsystems - Beijing China */
2230aff4bce5Syi zhang - Sun Microsystems - Beijing China if ((icp->conn_sess->sess_type == ISCSI_SESS_TYPE_NORMAL) &&
2231aff4bce5Syi zhang - Sun Microsystems - Beijing China ((icp->conn_state == ISCSI_CONN_STATE_FAILED) ||
2232aff4bce5Syi zhang - Sun Microsystems - Beijing China (icp->conn_state == ISCSI_CONN_STATE_POLLING))) {
2233aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.nonblock_socket = B_TRUE;
2234aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.conn_login_max =
2235aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_login_max;
2236aff4bce5Syi zhang - Sun Microsystems - Beijing China if (icp->conn_state == ISCSI_CONN_STATE_POLLING) {
2237aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.conn_login_interval =
2238aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_tunable_params.polling_login_delay;
2239aff4bce5Syi zhang - Sun Microsystems - Beijing China } else {
2240aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.conn_login_interval =
2241aff4bce5Syi zhang - Sun Microsystems - Beijing China ISCSI_LOGIN_RETRY_DELAY;
2242aff4bce5Syi zhang - Sun Microsystems - Beijing China }
2243aff4bce5Syi zhang - Sun Microsystems - Beijing China
2244aff4bce5Syi zhang - Sun Microsystems - Beijing China } else {
2245aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.nonblock_socket = B_FALSE;
2246aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.conn_login_max = 0;
2247aff4bce5Syi zhang - Sun Microsystems - Beijing China icp->conn_ic->ic_conn_params.conn_login_interval = 0;
2248aff4bce5Syi zhang - Sun Microsystems - Beijing China }
2249aff4bce5Syi zhang - Sun Microsystems - Beijing China /*
225030e7468fSPeter Dunlap * Attempt connection. Upon return we will either be ready to
225130e7468fSPeter Dunlap * login or disconnected. If idm_ini_conn_connect fails we
225230e7468fSPeter Dunlap * will eventually receive a CN_CONNECT_DESTROY at which point
225330e7468fSPeter Dunlap * we will destroy the connection allocated above (so there
225430e7468fSPeter Dunlap * is no need to explicitly free it here).
225530e7468fSPeter Dunlap */
225630e7468fSPeter Dunlap rval = idm_ini_conn_connect(icp->conn_ic);
225730e7468fSPeter Dunlap
225830e7468fSPeter Dunlap if (rval != IDM_STATUS_SUCCESS) {
2259fcf3ce44SJohn Forte cmn_err(CE_NOTE, "iscsi connection(%u) unable to "
2260fcf3ce44SJohn Forte "connect to target %s", icp->conn_oid,
2261fcf3ce44SJohn Forte icp->conn_sess->sess_name);
226230e7468fSPeter Dunlap idm_conn_rele(icp->conn_ic);
2263fcf3ce44SJohn Forte }
2264fcf3ce44SJohn Forte
226530e7468fSPeter Dunlap return (rval == IDM_STATUS_SUCCESS ?
226630e7468fSPeter Dunlap ISCSI_STATUS_SUCCESS : ISCSI_STATUS_INTERNAL_ERROR);
2267fcf3ce44SJohn Forte }
2268fcf3ce44SJohn Forte
226930e7468fSPeter Dunlap /*
227030e7468fSPeter Dunlap * iscsi_login_disconnect
227130e7468fSPeter Dunlap */
227230e7468fSPeter Dunlap static void
iscsi_login_disconnect(iscsi_conn_t * icp)227330e7468fSPeter Dunlap iscsi_login_disconnect(iscsi_conn_t *icp)
227430e7468fSPeter Dunlap {
227530e7468fSPeter Dunlap /* Tell IDM to disconnect is if we are not already disconnect */
227630e7468fSPeter Dunlap idm_ini_conn_disconnect_sync(icp->conn_ic);
227730e7468fSPeter Dunlap
227830e7468fSPeter Dunlap /*
227930e7468fSPeter Dunlap * The function above may return before the CN_CONNECT_LOST
228030e7468fSPeter Dunlap * notification. Wait for it.
228130e7468fSPeter Dunlap */
228230e7468fSPeter Dunlap mutex_enter(&icp->conn_state_mutex);
228330e7468fSPeter Dunlap while (icp->conn_state_idm_connected)
228430e7468fSPeter Dunlap cv_wait(&icp->conn_state_change,
228530e7468fSPeter Dunlap &icp->conn_state_mutex);
228630e7468fSPeter Dunlap mutex_exit(&icp->conn_state_mutex);
228730e7468fSPeter Dunlap }
228830e7468fSPeter Dunlap
228930e7468fSPeter Dunlap /*
229030e7468fSPeter Dunlap * iscsi_notice_key_values - Create an nvlist containing the values
229130e7468fSPeter Dunlap * that have been negotiated for this connection and pass them down to
229230e7468fSPeter Dunlap * IDM so it can pick up any values that are important.
229330e7468fSPeter Dunlap */
229430e7468fSPeter Dunlap static void
iscsi_notice_key_values(iscsi_conn_t * icp)229530e7468fSPeter Dunlap iscsi_notice_key_values(iscsi_conn_t *icp)
229630e7468fSPeter Dunlap {
229730e7468fSPeter Dunlap nvlist_t *neg_nvl;
229830e7468fSPeter Dunlap int rc;
229930e7468fSPeter Dunlap
230030e7468fSPeter Dunlap rc = nvlist_alloc(&neg_nvl, NV_UNIQUE_NAME, KM_SLEEP);
230130e7468fSPeter Dunlap ASSERT(rc == 0);
230230e7468fSPeter Dunlap
230330e7468fSPeter Dunlap /* Only crc32c is supported so the digest logic is simple */
230430e7468fSPeter Dunlap if (icp->conn_params.header_digest) {
230530e7468fSPeter Dunlap rc = nvlist_add_string(neg_nvl, "HeaderDigest", "crc32c");
230630e7468fSPeter Dunlap } else {
230730e7468fSPeter Dunlap rc = nvlist_add_string(neg_nvl, "HeaderDigest", "none");
230830e7468fSPeter Dunlap }
230930e7468fSPeter Dunlap ASSERT(rc == 0);
231030e7468fSPeter Dunlap
231130e7468fSPeter Dunlap if (icp->conn_params.data_digest) {
231230e7468fSPeter Dunlap rc = nvlist_add_string(neg_nvl, "DataDigest", "crc32c");
231330e7468fSPeter Dunlap } else {
231430e7468fSPeter Dunlap rc = nvlist_add_string(neg_nvl, "DataDigest", "none");
231530e7468fSPeter Dunlap }
231630e7468fSPeter Dunlap ASSERT(rc == 0);
231730e7468fSPeter Dunlap
231830e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "MaxRecvDataSegmentLength",
231930e7468fSPeter Dunlap (uint64_t)icp->conn_params.max_recv_data_seg_len);
232030e7468fSPeter Dunlap ASSERT(rc == 0);
232130e7468fSPeter Dunlap
232230e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "MaxBurstLength",
232330e7468fSPeter Dunlap (uint64_t)icp->conn_params.max_burst_length);
232430e7468fSPeter Dunlap ASSERT(rc == 0);
232530e7468fSPeter Dunlap
232630e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "MaxOutstandingR2T",
232730e7468fSPeter Dunlap (uint64_t)icp->conn_params.max_outstanding_r2t);
232830e7468fSPeter Dunlap ASSERT(rc == 0);
232930e7468fSPeter Dunlap
233030e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "ErrorRecoveryLevel",
233130e7468fSPeter Dunlap (uint64_t)icp->conn_params.error_recovery_level);
233230e7468fSPeter Dunlap ASSERT(rc == 0);
233330e7468fSPeter Dunlap
233430e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Wait",
233530e7468fSPeter Dunlap (uint64_t)icp->conn_params.default_time_to_wait);
233630e7468fSPeter Dunlap ASSERT(rc == 0);
233730e7468fSPeter Dunlap
233830e7468fSPeter Dunlap rc = nvlist_add_uint64(neg_nvl, "DefaultTime2Retain",
233930e7468fSPeter Dunlap (uint64_t)icp->conn_params.default_time_to_retain);
234030e7468fSPeter Dunlap ASSERT(rc == 0);
234130e7468fSPeter Dunlap
234230e7468fSPeter Dunlap /* Pass the list to IDM to examine, then free it */
234330e7468fSPeter Dunlap idm_notice_key_values(icp->conn_ic, neg_nvl);
234430e7468fSPeter Dunlap nvlist_free(neg_nvl);
2345fcf3ce44SJohn Forte }
2346