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