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