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