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