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