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