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