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