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