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