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.
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.
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]
22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 #include <sys/cpuvar.h>
27 #include <sys/types.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/scsi/generic/persist.h>
35 #include <sys/socket.h>
36 #include <sys/strsubr.h>
37 #include <sys/sysmacros.h>
42 #include <sys/stmf_ioctl.h>
43 #include <sys/portif.h>
44 #include <sys/idm/idm.h>
45 #include <sys/idm/idm_text.h>
47 #define ISCSIT_LOGIN_SM_STRINGS
49 #include "iscsit_auth.h"
52 list_node_t le_ctx_node
;
53 iscsit_login_event_t le_ctx_event
;
65 #define DEFAULT_RADIUS_PORT 1812
68 login_sm_complete(void *ict_void
);
71 login_sm_event_dispatch(iscsit_conn_login_t
*lsm
, iscsit_conn_t
*ict
,
72 login_event_ctx_t
*ctx
);
75 login_sm_init(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
78 login_sm_waiting(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
81 login_sm_processing(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
84 login_sm_responding(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
87 login_sm_responded(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
90 login_sm_ffp(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
93 login_sm_done(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
96 login_sm_error(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
);
99 login_sm_new_state(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
,
100 iscsit_login_state_t new_state
);
103 login_sm_send_ack(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
);
106 login_sm_validate_ack(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
);
109 login_sm_is_last_response(idm_pdu_t
*pdu
);
112 login_sm_handle_initial_login(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
);
115 login_sm_send_next_response(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
);
118 login_sm_process_request(iscsit_conn_t
*ict
);
121 login_sm_req_pdu_check(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
);
124 login_sm_process_nvlist(iscsit_conn_t
*ict
);
127 login_sm_check_security(iscsit_conn_t
*ict
);
130 login_sm_build_login_response(iscsit_conn_t
*ict
);
133 login_sm_ffp_actions(iscsit_conn_t
*ict
);
136 login_sm_validate_initial_parameters(iscsit_conn_t
*ict
);
139 login_sm_session_bind(iscsit_conn_t
*ict
);
142 login_sm_set_auth(iscsit_conn_t
*ict
);
145 login_sm_session_register(iscsit_conn_t
*ict
);
148 iscsit_handle_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
, char *nvp_name
);
151 iscsit_handle_common_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
152 const idm_kv_xlate_t
*ikvx
);
155 iscsit_handle_security_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
156 const idm_kv_xlate_t
*ikvx
);
159 iscsit_reply_security_key(iscsit_conn_t
*ict
);
162 iscsit_handle_operational_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
163 const idm_kv_xlate_t
*ikvx
);
166 iscsit_reply_numerical(iscsit_conn_t
*ict
,
167 const char *nvp_name
, const uint64_t value
);
170 iscsit_reply_string(iscsit_conn_t
*ict
,
171 const char *nvp_name
, const char *text
);
174 iscsit_handle_digest(iscsit_conn_t
*ict
, nvpair_t
*choices
,
175 const idm_kv_xlate_t
*ikvx
);
178 iscsit_handle_boolean(iscsit_conn_t
*ict
, nvpair_t
*nvp
, boolean_t value
,
179 const idm_kv_xlate_t
*ikvx
, boolean_t iscsit_value
);
182 iscsit_handle_numerical(iscsit_conn_t
*ict
, nvpair_t
*nvp
, uint64_t value
,
183 const idm_kv_xlate_t
*ikvx
,
184 uint64_t iscsi_min_value
, uint64_t iscsi_max_value
,
185 uint64_t iscsit_max_value
);
188 iscsit_process_negotiated_values(iscsit_conn_t
*ict
);
191 login_resp_complete_cb(idm_pdu_t
*pdu
, idm_status_t status
);
194 iscsit_add_declarative_keys(iscsit_conn_t
*ict
);
196 uint64_t max_dataseglen_target
= ISCSIT_MAX_RECV_DATA_SEGMENT_LENGTH
;
199 * global mutex defined in iscsit.c to enforce
200 * login_sm_session_bind as a critical section
202 extern kmutex_t login_sm_session_mutex
;
205 iscsit_login_sm_init(iscsit_conn_t
*ict
)
207 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
209 bzero(lsm
, sizeof (iscsit_conn_login_t
));
211 (void) nvlist_alloc(&lsm
->icl_negotiated_values
, NV_UNIQUE_NAME
,
215 * Hold connection until the login state machine completes
217 iscsit_conn_hold(ict
);
220 * Pre-allocating a login response PDU means we will always be
221 * able to respond to a login request -- even if we can't allocate
222 * a data buffer to hold the text responses we can at least send
225 lsm
->icl_login_resp_tmpl
= kmem_zalloc(sizeof (iscsi_login_rsp_hdr_t
),
228 idm_sm_audit_init(&lsm
->icl_state_audit
);
229 mutex_init(&lsm
->icl_mutex
, NULL
, MUTEX_DEFAULT
, NULL
);
230 list_create(&lsm
->icl_login_events
, sizeof (login_event_ctx_t
),
231 offsetof(login_event_ctx_t
, le_ctx_node
));
232 list_create(&lsm
->icl_pdu_list
, sizeof (idm_pdu_t
),
233 offsetof(idm_pdu_t
, isp_client_lnd
));
235 lsm
->icl_login_state
= ILS_LOGIN_INIT
;
236 lsm
->icl_login_last_state
= ILS_LOGIN_INIT
;
239 * Initialize operational parameters to default values. Anything
240 * we don't specifically negotiate stays at the default.
242 ict
->ict_op
.op_discovery_session
= B_FALSE
;
243 ict
->ict_op
.op_initial_r2t
= ISCSI_DEFAULT_INITIALR2T
;
244 ict
->ict_op
.op_immed_data
= ISCSI_DEFAULT_IMMEDIATE_DATA
;
245 ict
->ict_op
.op_data_pdu_in_order
= ISCSI_DEFAULT_DATA_PDU_IN_ORDER
;
246 ict
->ict_op
.op_data_sequence_in_order
=
247 ISCSI_DEFAULT_DATA_SEQUENCE_IN_ORDER
;
248 ict
->ict_op
.op_max_connections
= ISCSI_DEFAULT_MAX_CONNECTIONS
;
249 ict
->ict_op
.op_max_recv_data_segment_length
=
250 ISCSI_DEFAULT_MAX_RECV_SEG_LEN
;
251 ict
->ict_op
.op_max_burst_length
= ISCSI_DEFAULT_MAX_BURST_LENGTH
;
252 ict
->ict_op
.op_first_burst_length
= ISCSI_DEFAULT_FIRST_BURST_LENGTH
;
253 ict
->ict_op
.op_default_time_2_wait
= ISCSI_DEFAULT_TIME_TO_WAIT
;
254 ict
->ict_op
.op_default_time_2_retain
= ISCSI_DEFAULT_TIME_TO_RETAIN
;
255 ict
->ict_op
.op_max_outstanding_r2t
= ISCSI_DEFAULT_MAX_OUT_R2T
;
256 ict
->ict_op
.op_error_recovery_level
=
257 ISCSI_DEFAULT_ERROR_RECOVERY_LEVEL
;
259 return (IDM_STATUS_SUCCESS
);
263 login_resp_complete_cb(idm_pdu_t
*pdu
, idm_status_t status
)
265 iscsit_conn_t
*ict
= pdu
->isp_private
;
268 * Check that this is a login pdu
270 ASSERT((pdu
->isp_flags
& IDM_PDU_LOGIN_TX
) != 0);
273 if ((status
!= IDM_STATUS_SUCCESS
) ||
274 (ict
->ict_login_sm
.icl_login_resp_err_class
!= 0)) {
276 * Transport or login error occurred.
278 iscsit_login_sm_event(ict
, ILE_LOGIN_ERROR
, NULL
);
280 iscsit_conn_rele(ict
);
284 iscsit_login_sm_fini(iscsit_conn_t
*ict
)
286 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
288 mutex_enter(&lsm
->icl_mutex
);
289 list_destroy(&lsm
->icl_pdu_list
);
290 list_destroy(&lsm
->icl_login_events
);
292 kmem_free(lsm
->icl_login_resp_tmpl
, sizeof (iscsi_login_rsp_hdr_t
));
294 /* clean up the login response idm text buffer */
295 if (lsm
->icl_login_resp_itb
!= NULL
) {
296 idm_itextbuf_free(lsm
->icl_login_resp_itb
);
297 lsm
->icl_login_resp_itb
= NULL
;
300 nvlist_free(lsm
->icl_negotiated_values
);
301 mutex_destroy(&lsm
->icl_mutex
);
305 iscsit_login_sm_event(iscsit_conn_t
*ict
, iscsit_login_event_t event
,
309 * This is a bit ugly but if we're already in ILS_LOGIN_ERROR
310 * or ILS_LOGIN_DONE then just drop any additional events. They
311 * won't change the state and it's possible we've already called
312 * iscsit_login_sm_fini in which case the mutex is destroyed.
314 if ((ict
->ict_login_sm
.icl_login_state
== ILS_LOGIN_ERROR
) ||
315 (ict
->ict_login_sm
.icl_login_state
== ILS_LOGIN_DONE
))
318 mutex_enter(&ict
->ict_login_sm
.icl_mutex
);
319 iscsit_login_sm_event_locked(ict
, event
, pdu
);
320 mutex_exit(&ict
->ict_login_sm
.icl_mutex
);
323 iscsit_login_sm_event_locked(iscsit_conn_t
*ict
, iscsit_login_event_t event
,
326 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
327 login_event_ctx_t
*ctx
;
329 ASSERT(mutex_owned(&lsm
->icl_mutex
));
330 ctx
= kmem_zalloc(sizeof (*ctx
), KM_SLEEP
);
332 ctx
->le_ctx_event
= event
;
335 list_insert_tail(&lsm
->icl_login_events
, ctx
);
338 * Use the icl_busy flag to keep the state machine single threaded.
339 * This also serves as recursion avoidance since this flag will
340 * always be set if we call login_sm_event from within the
341 * state machine code.
343 if (!lsm
->icl_busy
) {
344 lsm
->icl_busy
= B_TRUE
;
345 while (!list_is_empty(&lsm
->icl_login_events
)) {
346 ctx
= list_head(&lsm
->icl_login_events
);
347 list_remove(&lsm
->icl_login_events
, ctx
);
348 idm_sm_audit_event(&lsm
->icl_state_audit
,
349 SAS_ISCSIT_LOGIN
, (int)lsm
->icl_login_state
,
350 (int)ctx
->le_ctx_event
, (uintptr_t)pdu
);
353 * If the lsm is in a terminal state, just drain
354 * any remaining events.
356 if ((lsm
->icl_login_state
== ILS_LOGIN_ERROR
) ||
357 (lsm
->icl_login_state
== ILS_LOGIN_DONE
)) {
358 kmem_free(ctx
, sizeof (*ctx
));
361 mutex_exit(&lsm
->icl_mutex
);
362 login_sm_event_dispatch(lsm
, ict
, ctx
);
363 mutex_enter(&lsm
->icl_mutex
);
365 lsm
->icl_busy
= B_FALSE
;
368 * When the state machine reaches ILS_LOGIN_DONE or
369 * ILS_LOGIN_ERROR state the login process has completed
370 * and it's time to cleanup. The state machine code will
371 * mark itself "complete" when this happens.
373 * To protect against spurious events (which shouldn't
374 * happen) set icl_busy again.
376 if (lsm
->icl_login_complete
) {
377 lsm
->icl_busy
= B_TRUE
;
378 if (taskq_dispatch(iscsit_global
.global_dispatch_taskq
,
379 login_sm_complete
, ict
, DDI_SLEEP
) == NULL
) {
380 cmn_err(CE_WARN
, "iscsit_login_sm_event_locked:"
381 " Failed to dispatch task");
388 login_sm_complete(void *ict_void
)
390 iscsit_conn_t
*ict
= ict_void
;
393 * State machine has run to completion, resources
394 * will be cleaned up when connection is destroyed.
396 iscsit_conn_rele(ict
);
400 login_sm_event_dispatch(iscsit_conn_login_t
*lsm
, iscsit_conn_t
*ict
,
401 login_event_ctx_t
*ctx
)
403 idm_pdu_t
*pdu
= ctx
->le_pdu
; /* Only valid for some events */
405 DTRACE_PROBE2(login__event
, iscsit_conn_t
*, ict
,
406 login_event_ctx_t
*, ctx
);
408 IDM_SM_LOG(CE_NOTE
, "login_sm_event_dispatch: ict %p event %s(%d)",
410 iscsit_ile_name
[ctx
->le_ctx_event
], ctx
->le_ctx_event
);
412 /* State independent actions */
413 switch (ctx
->le_ctx_event
) {
415 /* Perform basic sanity checks on the header */
416 if (login_sm_req_pdu_check(ict
, pdu
) != IDM_STATUS_SUCCESS
) {
419 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
420 ISCSI_LOGIN_STATUS_INVALID_REQUEST
);
422 * If we haven't processed any PDU's yet then use
423 * this one as a template for the response
425 if (ict
->ict_login_sm
.icl_login_resp_tmpl
->opcode
== 0)
426 login_sm_handle_initial_login(ict
, pdu
);
427 rpdu
= login_sm_build_login_response(ict
);
428 login_sm_send_next_response(ict
, rpdu
);
429 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
430 kmem_free(ctx
, sizeof (*ctx
));
438 /* State dependent actions */
439 switch (lsm
->icl_login_state
) {
441 login_sm_init(ict
, ctx
);
443 case ILS_LOGIN_WAITING
:
444 login_sm_waiting(ict
, ctx
);
446 case ILS_LOGIN_PROCESSING
:
447 login_sm_processing(ict
, ctx
);
449 case ILS_LOGIN_RESPONDING
:
450 login_sm_responding(ict
, ctx
);
452 case ILS_LOGIN_RESPONDED
:
453 login_sm_responded(ict
, ctx
);
456 login_sm_ffp(ict
, ctx
);
459 login_sm_done(ict
, ctx
);
461 case ILS_LOGIN_ERROR
:
462 login_sm_error(ict
, ctx
);
466 kmem_free(ctx
, sizeof (*ctx
));
470 login_sm_init(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
474 switch (ctx
->le_ctx_event
) {
479 * This is the first login PDU we've received so use
480 * it to build the login response template and set our CSG.
482 login_sm_handle_initial_login(ict
, pdu
);
485 * Accumulate all the login PDU's that make up this
486 * request on a queue.
488 mutex_enter(&ict
->ict_login_sm
.icl_mutex
);
489 list_insert_tail(&ict
->ict_login_sm
.icl_pdu_list
, pdu
);
490 mutex_exit(&ict
->ict_login_sm
.icl_mutex
);
492 if (pdu
->isp_hdr
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) {
493 login_sm_send_ack(ict
, pdu
);
494 login_sm_new_state(ict
, ctx
, ILS_LOGIN_WAITING
);
496 login_sm_new_state(ict
, ctx
, ILS_LOGIN_PROCESSING
);
499 case ILE_LOGIN_CONN_ERROR
:
500 case ILE_LOGIN_ERROR
:
501 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
509 login_sm_waiting(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
513 switch (ctx
->le_ctx_event
) {
516 mutex_enter(&ict
->ict_login_sm
.icl_mutex
);
517 list_insert_tail(&ict
->ict_login_sm
.icl_pdu_list
, pdu
);
518 mutex_exit(&ict
->ict_login_sm
.icl_mutex
);
519 if (!(pdu
->isp_hdr
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
)) {
520 login_sm_new_state(ict
, ctx
, ILS_LOGIN_PROCESSING
);
522 login_sm_send_ack(ict
, pdu
);
525 case ILE_LOGIN_ERROR
:
526 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
528 case ILE_LOGIN_RESP_COMPLETE
:
536 login_sm_processing(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
538 switch (ctx
->le_ctx_event
) {
539 case ILE_LOGIN_RESP_READY
:
540 login_sm_new_state(ict
, ctx
, ILS_LOGIN_RESPONDING
);
543 idm_pdu_complete(ctx
->le_pdu
, IDM_STATUS_SUCCESS
);
545 case ILE_LOGIN_CONN_ERROR
:
546 case ILE_LOGIN_ERROR
:
547 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
555 login_sm_responding(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
557 idm_pdu_t
*pdu
, *rpdu
;
559 switch (ctx
->le_ctx_event
) {
563 * We should only be in "responding" state if we have not
564 * sent the last PDU of a multi-PDU login response sequence.
565 * In that case we expect this received PDU to be an
566 * acknowledgement from the initiator (login PDU with C
567 * bit cleared and no data). If it's the acknowledgement
568 * we are expecting then we send the next PDU in the login
569 * response sequence. Otherwise it's a protocol error and
572 if (login_sm_validate_ack(ict
, pdu
) == IDM_STATUS_SUCCESS
) {
573 rpdu
= login_sm_build_login_response(ict
);
574 login_sm_send_next_response(ict
, rpdu
);
576 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
578 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
581 login_sm_new_state(ict
, ctx
, ILS_LOGIN_FFP
);
583 case ILE_LOGIN_RESP_COMPLETE
:
584 login_sm_new_state(ict
, ctx
, ILS_LOGIN_RESPONDED
);
586 case ILE_LOGIN_CONN_ERROR
:
587 case ILE_LOGIN_ERROR
:
588 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
596 login_sm_responded(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
599 iscsi_login_hdr_t
*lh
;
601 switch (ctx
->le_ctx_event
) {
604 lh
= (iscsi_login_hdr_t
*)pdu
->isp_hdr
;
606 * Set the CSG, NSG and Transit bits based on the this PDU.
607 * The CSG already validated in login_sm_req_pdu_check().
608 * We'll clear the transit bit if we encounter any login
609 * parameters in the request that required an additional
610 * login transfer (i.e. no acceptable
611 * choices in range or we needed to change a boolean
612 * value from "Yes" to "No").
614 ict
->ict_login_sm
.icl_login_csg
=
615 ISCSI_LOGIN_CURRENT_STAGE(lh
->flags
);
616 ict
->ict_login_sm
.icl_login_nsg
=
617 ISCSI_LOGIN_NEXT_STAGE(lh
->flags
);
618 ict
->ict_login_sm
.icl_login_transit
=
619 lh
->flags
& ISCSI_FLAG_LOGIN_TRANSIT
;
620 mutex_enter(&ict
->ict_login_sm
.icl_mutex
);
621 list_insert_tail(&ict
->ict_login_sm
.icl_pdu_list
, pdu
);
622 mutex_exit(&ict
->ict_login_sm
.icl_mutex
);
623 if (pdu
->isp_hdr
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) {
624 login_sm_send_ack(ict
, pdu
);
625 login_sm_new_state(ict
, ctx
, ILS_LOGIN_WAITING
);
627 login_sm_new_state(ict
, ctx
, ILS_LOGIN_PROCESSING
);
630 case ILE_LOGIN_CONN_ERROR
:
631 case ILE_LOGIN_ERROR
:
632 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
640 login_sm_ffp(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
642 switch (ctx
->le_ctx_event
) {
643 case ILE_LOGIN_RESP_COMPLETE
:
644 login_sm_new_state(ict
, ctx
, ILS_LOGIN_DONE
);
646 case ILE_LOGIN_CONN_ERROR
:
647 case ILE_LOGIN_ERROR
:
648 login_sm_new_state(ict
, ctx
, ILS_LOGIN_ERROR
);
658 login_sm_done(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
660 /* Terminal state, we should get no events */
661 switch (ctx
->le_ctx_event
) {
664 * We've already processed everything we're going to
665 * process. Drop any additional login PDU's.
667 idm_pdu_complete(ctx
->le_pdu
, IDM_STATUS_SUCCESS
);
669 case ILE_LOGIN_CONN_ERROR
:
679 login_sm_error(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
)
681 switch (ctx
->le_ctx_event
) {
684 * We've already processed everything we're going to
685 * process. Drop any additional login PDU's.
687 idm_pdu_complete(ctx
->le_pdu
, IDM_STATUS_SUCCESS
);
689 case ILE_LOGIN_CONN_ERROR
:
698 login_sm_new_state(iscsit_conn_t
*ict
, login_event_ctx_t
*ctx
,
699 iscsit_login_state_t new_state
)
701 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
707 ASSERT(new_state
!= ILS_UNDEFINED
);
708 ASSERT3U(new_state
, <, ILS_MAX_STATE
);
710 new_state
= (new_state
< ILS_MAX_STATE
) ?
711 new_state
: ILS_UNDEFINED
;
713 IDM_SM_LOG(CE_NOTE
, "login_sm_new_state: conn %p "
714 "%s (%d) --> %s (%d)\n", (void *)ict
->ict_ic
,
715 iscsit_ils_name
[lsm
->icl_login_state
], lsm
->icl_login_state
,
716 iscsit_ils_name
[new_state
], new_state
);
718 DTRACE_PROBE3(login__state__change
,
719 iscsit_conn_t
*, ict
, login_event_ctx_t
*, ctx
,
720 iscsit_login_state_t
, new_state
);
722 mutex_enter(&lsm
->icl_mutex
);
723 idm_sm_audit_state_change(&lsm
->icl_state_audit
, SAS_ISCSIT_LOGIN
,
724 (int)lsm
->icl_login_state
, (int)new_state
);
725 lsm
->icl_login_last_state
= lsm
->icl_login_state
;
726 lsm
->icl_login_state
= new_state
;
727 mutex_exit(&lsm
->icl_mutex
);
729 switch (lsm
->icl_login_state
) {
730 case ILS_LOGIN_WAITING
:
731 /* Do nothing, waiting for more login PDU's */
733 case ILS_LOGIN_PROCESSING
:
734 /* All login PDU's received, process login request */
735 login_sm_process_request(ict
);
737 case ILS_LOGIN_RESPONDING
:
738 rpdu
= login_sm_build_login_response(ict
);
739 login_sm_send_next_response(ict
, rpdu
);
741 case ILS_LOGIN_RESPONDED
:
742 /* clean up the login response idm text buffer */
743 if (lsm
->icl_login_resp_itb
!= NULL
) {
744 idm_itextbuf_free(lsm
->icl_login_resp_itb
);
745 lsm
->icl_login_resp_itb
= NULL
;
749 login_sm_ffp_actions(ict
);
752 case ILS_LOGIN_ERROR
:
754 * Flag the terminal state for the dispatcher
756 lsm
->icl_login_complete
= B_TRUE
;
758 case ILS_LOGIN_INIT
: /* Initial state, can't return */
767 login_sm_send_ack(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
)
769 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
773 * allocate the response pdu
775 lack
= idm_pdu_alloc(sizeof (iscsi_hdr_t
), 0);
776 idm_pdu_init(lack
, ict
->ict_ic
, ict
, login_resp_complete_cb
);
777 lack
->isp_flags
|= IDM_PDU_LOGIN_TX
;
780 * copy the response template into the response pdu
782 bcopy(lsm
->icl_login_resp_tmpl
, lack
->isp_hdr
, sizeof (iscsi_hdr_t
));
784 iscsit_conn_hold(ict
);
790 login_sm_validate_ack(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
)
792 iscsi_hdr_t
*ihp
= pdu
->isp_hdr
;
793 if (ihp
->flags
& ISCSI_FLAG_TEXT_CONTINUE
) {
794 return (IDM_STATUS_FAIL
);
796 if (ntoh24(ihp
->dlength
) != 0) {
797 return (IDM_STATUS_FAIL
);
799 return (IDM_STATUS_SUCCESS
);
803 login_sm_is_last_response(idm_pdu_t
*pdu
)
806 if (pdu
->isp_hdr
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) {
814 login_sm_handle_initial_login(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
)
816 iscsi_login_hdr_t
*lh_req
= (iscsi_login_hdr_t
*)pdu
->isp_hdr
;
817 iscsi_login_rsp_hdr_t
*lh_resp
=
818 ict
->ict_login_sm
.icl_login_resp_tmpl
;
821 * First login PDU, this connection should not have a sesssion
824 ASSERT(ict
->ict_sess
== NULL
);
827 * Save off TSIH and ISID for later use in finding a session
829 ict
->ict_login_sm
.icl_cmdsn
= ntohl(lh_req
->cmdsn
);
830 ict
->ict_login_sm
.icl_tsih
= ntohs(lh_req
->tsid
);
831 bcopy(lh_req
->isid
, ict
->ict_login_sm
.icl_isid
, ISCSI_ISID_LEN
);
834 * We'll need the CID as well
836 ict
->ict_cid
= ntohs(lh_req
->cid
);
839 * Set the CSG, NSG and Transit bits based on the first PDU
840 * in the login sequence. The CSG already validated in
841 * login_sm_req_pdu_check(). We'll clear the transit bit if
842 * we encounter any login parameters in the request that
843 * required an additional login transfer (i.e. no acceptable
844 * choices in range or we needed to change a boolean
845 * value from "Yes" to "No").
847 ict
->ict_login_sm
.icl_login_csg
=
848 ISCSI_LOGIN_CURRENT_STAGE(lh_req
->flags
);
849 ict
->ict_login_sm
.icl_login_nsg
=
850 ISCSI_LOGIN_NEXT_STAGE(lh_req
->flags
);
851 ict
->ict_login_sm
.icl_login_transit
=
852 lh_req
->flags
& ISCSI_FLAG_LOGIN_TRANSIT
;
855 * Initialize header for login reject response. This will also
856 * be copied for use as a template for other login responses
858 lh_resp
->opcode
= ISCSI_OP_LOGIN_RSP
;
859 lh_resp
->max_version
= ISCSIT_MAX_VERSION
;
862 * We already validated that we can support one of the initiator's
863 * versions in login_sm_req_pdu_check().
865 #if (ISCSIT_MAX_VERSION > 0)
866 if (ISCSIT_MAX_VERSION
>= lh_req
->min_version
) {
867 lh_resp
->active_version
=
868 MIN(lh_req
->max_version
, ISCSIT_MAX_VERSION
);
870 ASSERT(ISCSIT_MAX_VERSION
<= lh_req
->max_version
);
871 lh_resp
->active_version
= ISCSIT_MAX_VERSION
;
875 lh_resp
->hlength
= 0; /* No AHS */
876 bcopy(lh_req
->isid
, lh_resp
->isid
, ISCSI_ISID_LEN
);
877 lh_resp
->tsid
= lh_req
->tsid
;
878 lh_resp
->itt
= lh_req
->itt
;
881 * StatSn, ExpCmdSn and MaxCmdSn will be set immediately before
887 login_sm_send_next_response(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
)
889 iscsi_login_rsp_hdr_t
*lh_resp
= (iscsi_login_rsp_hdr_t
*)pdu
->isp_hdr
;
891 /* Make sure this PDU is part of the login phase */
892 ASSERT((pdu
->isp_flags
& IDM_PDU_LOGIN_TX
) != 0);
895 * Fill in header values
897 hton24(lh_resp
->dlength
, pdu
->isp_datalen
);
900 * If the login is successful, this login response will contain
901 * the next StatSN and advance the StatSN for the connection.
903 if (lh_resp
->status_class
== ISCSI_STATUS_CLASS_SUCCESS
) {
904 ASSERT(ict
->ict_sess
!= NULL
);
906 if ((lh_resp
->flags
& ISCSI_FLAG_LOGIN_TRANSIT
) &&
907 (ISCSI_LOGIN_NEXT_STAGE(lh_resp
->flags
) ==
908 ISCSI_FULL_FEATURE_PHASE
) &&
909 !(lh_resp
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
)) {
910 iscsit_login_sm_event(ict
, ILE_LOGIN_FFP
, NULL
);
912 if (login_sm_is_last_response(pdu
) == B_TRUE
) {
914 * The last of a potentially mult-PDU response finished.
916 iscsit_login_sm_event(ict
, ILE_LOGIN_RESP_COMPLETE
,
920 iscsit_conn_hold(ict
);
921 pdu
->isp_flags
|= IDM_PDU_SET_STATSN
| IDM_PDU_ADVANCE_STATSN
;
925 * If status_class != ISCSI_STATUS_CLASS_SUCCESS then
926 * StatSN is not valid and we can call idm_pdu_tx instead
927 * of iscsit_pdu_tx. This is very good thing since in
928 * some cases of login failure we may not have a session.
929 * Since iscsit_calc_rspsn grabs the session mutex while
930 * it is retrieving values for expcmdsn and maxcmdsn this
931 * would cause a panic.
933 * Since we still want a value for expcmdsn, fill in an
934 * appropriate value based on the login request before
935 * sending the response. Cmdsn/expcmdsn do not advance during
938 lh_resp
->expcmdsn
= htonl(ict
->ict_login_sm
.icl_cmdsn
);
939 lh_resp
->maxcmdsn
= htonl(ict
->ict_login_sm
.icl_cmdsn
+ 1);
941 iscsit_conn_hold(ict
);
948 login_sm_process_request(iscsit_conn_t
*ict
)
950 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
951 uint8_t error_class
= 0;
952 uint8_t error_detail
= 0;
955 * First walk all the PDU's that make up this login request
956 * and compile all the iSCSI key-value pairs into nvlist format.
959 ASSERT(lsm
->icl_request_nvlist
== NULL
);
960 /* create an nvlist for request key/value pairs */
961 if (idm_pdu_list_to_nvlist(&lsm
->icl_pdu_list
,
962 &lsm
->icl_request_nvlist
, &error_detail
) != IDM_STATUS_SUCCESS
) {
963 error_class
= ISCSI_STATUS_CLASS_TARGET_ERR
;
964 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
968 /* Allocate a new nvlist for response key/value pairs */
969 ASSERT(lsm
->icl_response_nvlist
== NULL
);
970 if (nvlist_alloc(&lsm
->icl_response_nvlist
, NV_UNIQUE_NAME
,
972 error_class
= ISCSI_STATUS_CLASS_TARGET_ERR
;
973 error_detail
= ISCSI_LOGIN_STATUS_NO_RESOURCES
;
974 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
979 * This would be a very good time to make sure we have
980 * negotiated the required values for the login phase. For
981 * example we definitely should have defined InitiatorName,
982 * and Target name regardless of our current login phase.
984 if (!ict
->ict_op
.op_initial_params_set
) {
985 if (login_sm_validate_initial_parameters(ict
) !=
986 IDM_STATUS_SUCCESS
) {
991 * Now setup our session association. This includes
992 * create a new session or looking up an existing session,
993 * and if this is not a discovery session then we will
994 * also register this session with STMF.
996 if (login_sm_session_bind(ict
) != IDM_STATUS_SUCCESS
) {
1000 if (login_sm_set_auth(ict
) != IDM_STATUS_SUCCESS
) {
1005 * Prepend TargetAlias and PortalGroupTag
1007 if (ict
->ict_op
.op_discovery_session
== B_FALSE
) {
1008 if ((lsm
->icl_auth
.ca_tgt_alias
[0]) != '\0') {
1009 (void) iscsit_reply_string(ict
,
1011 &lsm
->icl_auth
.ca_tgt_alias
[0]);
1013 (void) iscsit_reply_numerical(ict
,
1014 "TargetPortalGroupTag",
1015 (uint64_t)lsm
->icl_tpgt_tag
);
1018 ict
->ict_op
.op_initial_params_set
= B_TRUE
;
1021 if (login_sm_process_nvlist(ict
) != IDM_STATUS_SUCCESS
) {
1025 if (login_sm_check_security(ict
) != IDM_STATUS_SUCCESS
) {
1029 /* clean up request_nvlist */
1030 if (lsm
->icl_request_nvlist
!= NULL
) {
1031 nvlist_free(lsm
->icl_request_nvlist
);
1032 lsm
->icl_request_nvlist
= NULL
;
1035 /* convert any responses to textbuf form */
1036 ASSERT(lsm
->icl_login_resp_itb
== NULL
);
1037 if (lsm
->icl_response_nvlist
) {
1038 lsm
->icl_login_resp_itb
= idm_nvlist_to_itextbuf(
1039 lsm
->icl_response_nvlist
);
1040 if (lsm
->icl_login_resp_itb
== NULL
) {
1041 /* Still need to send the resp so continue */
1042 SET_LOGIN_ERROR(ict
,
1043 ISCSI_STATUS_CLASS_TARGET_ERR
,
1044 ISCSI_LOGIN_STATUS_NO_RESOURCES
);
1046 /* clean up response_nvlist */
1047 nvlist_free(lsm
->icl_response_nvlist
);
1048 lsm
->icl_response_nvlist
= NULL
;
1051 /* tell the state machine to send the textbuf */
1052 iscsit_login_sm_event(ict
, ILE_LOGIN_RESP_READY
, NULL
);
1057 /* clean up request_nvlist and response_nvlist */
1058 if (lsm
->icl_request_nvlist
!= NULL
) {
1059 nvlist_free(lsm
->icl_request_nvlist
);
1060 lsm
->icl_request_nvlist
= NULL
;
1062 if (lsm
->icl_response_nvlist
!= NULL
) {
1063 nvlist_free(lsm
->icl_response_nvlist
);
1064 lsm
->icl_response_nvlist
= NULL
;
1066 /* Make sure we already set the login error */
1067 if (ict
->ict_login_sm
.icl_login_resp_err_class
==
1068 ISCSI_STATUS_CLASS_SUCCESS
) {
1069 SET_LOGIN_ERROR(ict
,
1070 ISCSI_STATUS_CLASS_TARGET_ERR
,
1071 ISCSI_LOGIN_STATUS_TARGET_ERROR
);
1073 iscsit_login_sm_event(ict
, ILE_LOGIN_RESP_READY
, NULL
);
1078 login_sm_ffp_actions(iscsit_conn_t
*ict
)
1080 iscsit_process_negotiated_values(ict
);
1084 login_sm_validate_initial_parameters(iscsit_conn_t
*ict
)
1088 uint8_t error_class
= ISCSI_STATUS_CLASS_INITIATOR_ERR
;
1089 uint8_t error_detail
= ISCSI_LOGIN_STATUS_MISSING_FIELDS
;
1090 idm_status_t status
= IDM_STATUS_FAIL
;
1091 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1094 * Make sure we received the required information from the initial
1095 * login. Add these declaratives to the negotiated list and
1096 * remove them from the request list as we go. If anything fails,
1097 * the caller will clean-up the nvlists.
1103 if ((nvrc
= nvlist_lookup_string(lsm
->icl_request_nvlist
,
1104 "InitiatorName", &string_val
)) != 0) {
1105 goto initial_params_done
;
1107 if ((nvrc
= nvlist_add_string(lsm
->icl_negotiated_values
,
1108 "InitiatorName", string_val
)) != 0) {
1109 goto initial_params_done
;
1111 if ((nvrc
= nvlist_lookup_string(lsm
->icl_negotiated_values
,
1112 "InitiatorName", &string_val
)) != 0) {
1113 goto initial_params_done
;
1115 lsm
->icl_initiator_name
= string_val
;
1116 idm_conn_set_initiator_name(ict
->ict_ic
, lsm
->icl_initiator_name
);
1117 if ((nvrc
= nvlist_remove(lsm
->icl_request_nvlist
,
1118 "InitiatorName", DATA_TYPE_STRING
)) != 0) {
1119 goto initial_params_done
;
1125 ict
->ict_op
.op_discovery_session
= B_FALSE
;
1126 nvrc
= nvlist_lookup_string(lsm
->icl_request_nvlist
,
1127 "SessionType", &string_val
);
1128 if (nvrc
!= ENOENT
&& nvrc
!= 0) {
1129 goto initial_params_done
;
1132 if (strcmp(string_val
, "Discovery") == 0) {
1133 ict
->ict_op
.op_discovery_session
= B_TRUE
;
1134 } else if (strcmp(string_val
, "Normal") != 0) {
1135 goto initial_params_done
;
1137 if ((nvrc
= nvlist_add_string(lsm
->icl_negotiated_values
,
1138 "SessionType", string_val
)) != 0) {
1139 goto initial_params_done
;
1141 if ((nvrc
= nvlist_remove(lsm
->icl_request_nvlist
,
1142 "SessionType", DATA_TYPE_STRING
)) != 0) {
1143 goto initial_params_done
;
1148 * Must have either TargetName or SessionType==Discovery
1150 lsm
->icl_target_name
= NULL
;
1151 nvrc
= nvlist_lookup_string(lsm
->icl_request_nvlist
,
1152 "TargetName", &string_val
);
1153 if (nvrc
!= ENOENT
&& nvrc
!= 0) {
1154 goto initial_params_done
;
1157 if ((nvrc
= nvlist_add_string(lsm
->icl_negotiated_values
,
1158 "TargetName", string_val
)) != 0) {
1159 goto initial_params_done
;
1161 if ((nvrc
= nvlist_lookup_string(lsm
->icl_negotiated_values
,
1162 "TargetName", &string_val
)) != 0) {
1163 goto initial_params_done
;
1165 lsm
->icl_target_name
= string_val
;
1166 idm_conn_set_target_name(ict
->ict_ic
, lsm
->icl_target_name
);
1167 if ((nvrc
= nvlist_remove(lsm
->icl_request_nvlist
,
1168 "TargetName", DATA_TYPE_STRING
)) != 0) {
1169 goto initial_params_done
;
1171 } else if (ict
->ict_op
.op_discovery_session
== B_FALSE
) {
1173 * Missing target name
1175 goto initial_params_done
;
1178 idm_conn_set_isid(ict
->ict_ic
, lsm
->icl_isid
);
1179 (void) snprintf(ict
->ict_ic
->ic_tsih
, ISCSI_MAX_TSIH_LEN
+ 1, "0x%04x",
1182 IDM_SM_LOG(CE_NOTE
, "conn %p: initiator=%s", (void *)ict
->ict_ic
,
1183 (lsm
->icl_initiator_name
== NULL
) ? "N/A" :
1184 lsm
->icl_initiator_name
);
1185 IDM_SM_LOG(CE_NOTE
, "conn %p: target=%s", (void *)ict
->ict_ic
,
1186 (lsm
->icl_target_name
== NULL
) ? "N/A" :
1187 lsm
->icl_target_name
);
1188 IDM_SM_LOG(CE_NOTE
, "conn %p: sessiontype=%s", (void *)ict
->ict_ic
,
1189 ict
->ict_op
.op_discovery_session
? "Discovery" : "Normal");
1192 status
= IDM_STATUS_SUCCESS
;
1193 error_class
= ISCSI_STATUS_CLASS_SUCCESS
;
1194 error_detail
= ISCSI_LOGIN_STATUS_ACCEPT
;
1196 initial_params_done
:
1197 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
1203 * login_sm_session_bind
1205 * This function looks at the data from the initial login request
1206 * of a new connection and either looks up and existing session,
1207 * creates a new session, or returns an error. RFC3720 section 5.3.1
1208 * defines these rules:
1210 * +------------------------------------------------------------------+
1211 * |ISID | TSIH | CID | Target action |
1212 * +------------------------------------------------------------------+
1213 * |new | non-zero | any | fail the login |
1214 * | | | | ("session does not exist") |
1215 * +------------------------------------------------------------------+
1216 * |new | zero | any | instantiate a new session |
1217 * +------------------------------------------------------------------+
1218 * |existing | zero | any | do session reinstatement |
1219 * | | | | (see section 5.3.5) |
1220 * +------------------------------------------------------------------+
1221 * |existing | non-zero | new | add a new connection to |
1222 * | | existing | | the session |
1223 * +------------------------------------------------------------------+
1224 * |existing | non-zero |existing| do connection reinstatement|
1225 * | | existing | | (see section 5.3.4) |
1226 * +------------------------------------------------------------------+
1227 * |existing | non-zero | any | fail the login |
1228 * | | new | | ("session does not exist") |
1229 * +------------------------------------------------------------------+
1234 * Map an <ipv6,port> address to an <ipv4,port> address if possible.
1237 * 0 - address not mapable
1241 iscsit_is_v4_mapped(struct sockaddr_storage
*sa
, struct sockaddr_storage
*v4sa
)
1243 struct sockaddr_in
*sin
;
1245 struct sockaddr_in6
*sin6
;
1246 struct in6_addr
*in6
;
1249 sin6
= (struct sockaddr_in6
*)sa
;
1250 in6
= &sin6
->sin6_addr
;
1251 if ((sa
->ss_family
== AF_INET6
) &&
1252 (IN6_IS_ADDR_V4MAPPED(in6
) || IN6_IS_ADDR_V4COMPAT(in6
))) {
1253 sin
= (struct sockaddr_in
*)v4sa
;
1254 in
= &sin
->sin_addr
;
1255 v4sa
->ss_family
= AF_INET
;
1256 sin
->sin_port
= sin6
->sin6_port
;
1257 IN6_V4MAPPED_TO_INADDR(in6
, in
);
1264 login_sm_session_bind(iscsit_conn_t
*ict
)
1266 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1267 iscsit_tgt_t
*tgt
= NULL
;
1268 iscsit_tpgt_t
*tpgt
= NULL
;
1269 iscsit_portal_t
*portal
= NULL
;
1270 iscsit_sess_t
*existing_sess
= NULL
;
1271 iscsit_sess_t
*new_sess
= NULL
;
1272 iscsit_conn_t
*existing_ict
= NULL
;
1273 uint8_t error_class
;
1274 uint8_t error_detail
;
1277 * The multi-threaded execution of binding login sessions to target
1278 * introduced race conditions in the session creation/binding and
1279 * allowed duplicate sessions to tbe created. The addition of the
1280 * global mutex login_sm_session_mutex makes this function single
1281 * threaded to avoid such race conditions. Although this causes
1282 * a small portion of the login to be serialized, it is unlikely
1283 * that there would be numerous simultaneous logins to become a
1284 * performance issue.
1286 mutex_enter(&login_sm_session_mutex
);
1289 * Look up target and then check if there are sessions or connections
1290 * that match this request (see below). Any holds taken on objects
1291 * must be released at the end of the function (let's keep things
1294 * If target name is set then we should have a corresponding target
1295 * context configured.
1297 if (lsm
->icl_target_name
!= NULL
) {
1299 * iscsit_tgt_lookup implicitly takes a ref on the target
1301 ISCSIT_GLOBAL_LOCK(RW_READER
);
1302 tgt
= iscsit_tgt_lookup_locked(lsm
->icl_target_name
);
1304 ISCSIT_GLOBAL_UNLOCK();
1305 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1306 ISCSI_LOGIN_STATUS_TGT_NOT_FOUND
);
1307 goto session_bind_error
;
1309 mutex_enter(&tgt
->target_mutex
);
1310 tpgt
= avl_first(&tgt
->target_tpgt_list
);
1312 if (IS_DEFAULT_TPGT(tpgt
)) {
1313 lsm
->icl_tpgt_tag
= ISCSIT_DEFAULT_TPGT
;
1316 * Find the portal group tag for the
1319 struct sockaddr_storage v4sa
, *sa
;
1321 sa
= &ict
->ict_ic
->ic_laddr
;
1322 portal
= iscsit_tgt_lookup_portal(tgt
,
1324 if (portal
== NULL
&&
1325 iscsit_is_v4_mapped(sa
, &v4sa
)) {
1327 * Try again if the local address
1328 * was v6 mappable to v4.
1330 portal
= iscsit_tgt_lookup_portal(tgt
,
1334 if (portal
== NULL
) {
1336 * Initiator came in on wrong address
1338 SET_LOGIN_ERROR(ict
,
1339 ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1340 ISCSI_LOGIN_STATUS_TGT_NOT_FOUND
);
1341 mutex_exit(&tgt
->target_mutex
);
1342 ISCSIT_GLOBAL_UNLOCK();
1343 goto session_bind_error
;
1347 * Need to release holds on the portal and
1348 * tpgt after processing is complete.
1350 lsm
->icl_tpgt_tag
= tpgt
->tpgt_tag
;
1351 iscsit_portal_rele(portal
);
1352 iscsit_tpgt_rele(tpgt
);
1355 mutex_enter(&iscsit_global
.global_state_mutex
);
1356 if ((tgt
->target_state
!= TS_STMF_ONLINE
) ||
1357 ((iscsit_global
.global_svc_state
!= ISE_ENABLED
) &&
1358 ((iscsit_global
.global_svc_state
!= ISE_BUSY
)))) {
1359 mutex_exit(&iscsit_global
.global_state_mutex
);
1360 SET_LOGIN_ERROR(ict
,
1361 ISCSI_STATUS_CLASS_TARGET_ERR
,
1362 ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE
);
1363 mutex_exit(&tgt
->target_mutex
);
1364 ISCSIT_GLOBAL_UNLOCK();
1365 goto session_bind_error
;
1367 mutex_exit(&iscsit_global
.global_state_mutex
);
1368 mutex_exit(&tgt
->target_mutex
);
1369 ISCSIT_GLOBAL_UNLOCK();
1373 ASSERT((tgt
!= NULL
) || (ict
->ict_op
.op_discovery_session
== B_TRUE
));
1376 * Check if there is an existing session matching this ISID. If
1377 * tgt == NULL then we'll look for the session on the global list
1378 * of discovery session. If we find a session then the ISID
1381 existing_sess
= iscsit_tgt_lookup_sess(tgt
, lsm
->icl_initiator_name
,
1382 lsm
->icl_isid
, lsm
->icl_tsih
, lsm
->icl_tpgt_tag
);
1383 if (existing_sess
!= NULL
) {
1384 existing_ict
= iscsit_sess_lookup_conn(existing_sess
,
1389 * If this is a discovery session, make sure it has appropriate
1392 if ((ict
->ict_op
.op_discovery_session
== B_TRUE
) &&
1393 ((lsm
->icl_tsih
!= ISCSI_UNSPEC_TSIH
) || (existing_sess
!= NULL
))) {
1394 /* XXX Do we need to check for existing ISID (sess != NULL)? */
1395 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1396 ISCSI_LOGIN_STATUS_INVALID_REQUEST
);
1397 goto session_bind_error
;
1401 * Check the two error conditions from the table.
1403 * ISID=new, TSIH=non-zero
1405 if ((existing_sess
== NULL
) && (lsm
->icl_tsih
!= ISCSI_UNSPEC_TSIH
)) {
1406 /* fail the login */
1407 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1408 ISCSI_LOGIN_STATUS_NO_SESSION
);
1409 goto session_bind_error
;
1412 /* ISID=existing, TSIH=non-zero new */
1413 if ((existing_sess
!= NULL
) && (lsm
->icl_tsih
!= 0) &&
1414 (existing_sess
->ist_tsih
!= lsm
->icl_tsih
)) {
1415 /* fail the login */
1416 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1417 ISCSI_LOGIN_STATUS_NO_SESSION
);
1418 goto session_bind_error
;
1422 * Handle the remaining table cases in order
1424 if (existing_sess
== NULL
) {
1425 /* Should have caught this above */
1426 ASSERT(lsm
->icl_tsih
== ISCSI_UNSPEC_TSIH
);
1428 * ISID=new, TSIH=zero --> instantiate a new session
1430 new_sess
= iscsit_sess_create(tgt
, ict
, lsm
->icl_cmdsn
,
1431 lsm
->icl_isid
, lsm
->icl_tpgt_tag
, lsm
->icl_initiator_name
,
1432 lsm
->icl_target_name
, &error_class
, &error_detail
);
1433 ASSERT(new_sess
!= NULL
);
1435 /* Session create may have failed even if it returned a value */
1436 if (error_class
!= ISCSI_STATUS_CLASS_SUCCESS
) {
1437 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
1438 goto session_bind_error
;
1442 * If we don't already have an STMF session and this is not
1443 * a discovery session then we need to allocate and register
1446 if (!ict
->ict_op
.op_discovery_session
) {
1447 if (login_sm_session_register(ict
) !=
1448 IDM_STATUS_SUCCESS
) {
1449 /* login_sm_session_register sets error codes */
1450 goto session_bind_error
;
1455 if (lsm
->icl_tsih
== ISCSI_UNSPEC_TSIH
) {
1457 * ISID=existing, TSIH=zero --> Session reinstatement
1459 new_sess
= iscsit_sess_reinstate(tgt
, existing_sess
,
1460 ict
, &error_class
, &error_detail
);
1461 ASSERT(new_sess
!= NULL
);
1463 if (error_class
!= ISCSI_STATUS_CLASS_SUCCESS
) {
1464 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
1465 goto session_bind_error
;
1469 * If we don't already have an STMF session and this is
1470 * not a discovery session then we need to allocate and
1473 if (!ict
->ict_op
.op_discovery_session
) {
1474 if (login_sm_session_register(ict
) !=
1475 IDM_STATUS_SUCCESS
) {
1477 * login_sm_session_register sets
1480 goto session_bind_error
;
1485 * The following code covers these two cases:
1486 * ISID=existing, TSIH=non-zero existing, CID=new
1487 * --> add new connection to MC/S session
1488 * ISID=existing, TSIH=non-zero existing, CID=existing
1489 * --> do connection reinstatement
1491 * Session continuation uses this path as well
1493 cmn_err(CE_NOTE
, "login_sm_session_bind: add new "
1494 "conn/sess continue");
1495 if (existing_ict
!= NULL
) {
1497 * ISID=existing, TSIH=non-zero existing,
1498 * CID=existing --> do connection reinstatement
1500 if (iscsit_conn_reinstate(existing_ict
, ict
) !=
1501 IDM_STATUS_SUCCESS
) {
1503 * Most likely this means the connection
1504 * the initiator is trying to reinstate
1505 * is not in an acceptable state.
1507 SET_LOGIN_ERROR(ict
,
1508 ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1509 ISCSI_LOGIN_STATUS_INIT_ERR
);
1510 goto session_bind_error
;
1514 iscsit_sess_sm_event(existing_sess
, SE_CONN_IN_LOGIN
,
1520 iscsit_tgt_rele(tgt
);
1521 if (existing_sess
!= NULL
)
1522 iscsit_sess_rele(existing_sess
);
1523 if (existing_ict
!= NULL
)
1524 iscsit_conn_rele(existing_ict
);
1526 mutex_exit(&login_sm_session_mutex
);
1527 return (IDM_STATUS_SUCCESS
);
1531 iscsit_tgt_rele(tgt
);
1532 if (existing_sess
!= NULL
)
1533 iscsit_sess_rele(existing_sess
);
1534 if (existing_ict
!= NULL
)
1535 iscsit_conn_rele(existing_ict
);
1538 * If session bind fails we will fail the login but don't destroy
1539 * the session until later.
1541 mutex_exit(&login_sm_session_mutex
);
1542 return (IDM_STATUS_FAIL
);
1547 login_sm_set_auth(iscsit_conn_t
*ict
)
1549 idm_status_t idmrc
= IDM_STATUS_SUCCESS
;
1550 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1554 char *radiusserver
= "";
1555 char *radiussecret
= "";
1556 char *chapuser
= "";
1557 char *chapsecret
= "";
1558 char *targetchapuser
= "";
1559 char *targetchapsecret
= "";
1560 char *targetalias
= "";
1563 ISCSIT_GLOBAL_LOCK(RW_READER
);
1566 * Set authentication method to none for discovery session.
1568 if (ict
->ict_op
.op_discovery_session
== B_TRUE
) {
1569 lsm
->icl_auth
.ca_method_valid_list
[0] = AM_NONE
;
1570 ISCSIT_GLOBAL_UNLOCK();
1575 * Get all the authentication parameters we need -- since we hold
1576 * the global config lock we guarantee that the parameters will
1577 * be consistent with each other.
1579 (void) nvlist_lookup_string(iscsit_global
.global_props
,
1581 (void) nvlist_lookup_string(iscsit_global
.global_props
,
1582 PROP_RADIUS_SERVER
, &radiusserver
);
1583 (void) nvlist_lookup_string(iscsit_global
.global_props
,
1584 PROP_RADIUS_SECRET
, &radiussecret
);
1586 ini
= iscsit_ini_lookup_locked(lsm
->icl_initiator_name
);
1588 /* Get Initiator CHAP parameters */
1589 (void) nvlist_lookup_string(ini
->ini_props
, PROP_CHAP_USER
,
1591 (void) nvlist_lookup_string(ini
->ini_props
, PROP_CHAP_SECRET
,
1595 tgt
= ict
->ict_sess
->ist_tgt
;
1597 /* See if we have a target-specific authentication setting */
1598 (void) nvlist_lookup_string(tgt
->target_props
, PROP_AUTH
,
1600 /* Get target CHAP parameters */
1601 (void) nvlist_lookup_string(tgt
->target_props
,
1602 PROP_TARGET_CHAP_USER
, &targetchapuser
);
1603 (void) nvlist_lookup_string(tgt
->target_props
,
1604 PROP_TARGET_CHAP_SECRET
, &targetchapsecret
);
1606 (void) nvlist_lookup_string(tgt
->target_props
,
1607 PROP_ALIAS
, &targetalias
);
1610 /* Set authentication method */
1612 if (strcmp(auth
, PA_AUTH_RADIUS
) == 0) {
1613 /* CHAP authentication using RADIUS server */
1614 lsm
->icl_auth
.ca_method_valid_list
[i
++] = AM_CHAP
;
1615 lsm
->icl_auth
.ca_use_radius
= B_TRUE
;
1616 } else if (strcmp(auth
, PA_AUTH_CHAP
) == 0) {
1617 /* Local CHAP authentication */
1618 lsm
->icl_auth
.ca_method_valid_list
[i
++] = AM_CHAP
;
1619 lsm
->icl_auth
.ca_use_radius
= B_FALSE
;
1620 } else if ((strcmp(auth
, PA_AUTH_NONE
) == 0) ||
1621 (strcmp(auth
, "") == 0)) {
1622 /* No authentication */
1623 lsm
->icl_auth
.ca_method_valid_list
[i
++] = AM_NONE
;
1627 * If initiator/target CHAP username is not set then use the
1628 * node name. If lsm->icl_target_name == NULL then this is
1629 * a discovery session so we don't need to work about the target.
1631 if (strcmp(chapuser
, "") == 0) {
1632 (void) strlcpy(lsm
->icl_auth
.ca_ini_chapuser
,
1633 lsm
->icl_initiator_name
,
1634 min(iscsitAuthStringMaxLength
, MAX_ISCSI_NODENAMELEN
));
1636 (void) strlcpy(lsm
->icl_auth
.ca_ini_chapuser
, chapuser
,
1637 iscsitAuthStringMaxLength
);
1639 if ((lsm
->icl_target_name
!= NULL
) &&
1640 (strcmp(targetchapuser
, "") == 0)) {
1641 (void) strlcpy(lsm
->icl_auth
.ca_tgt_chapuser
,
1642 lsm
->icl_target_name
,
1643 min(iscsitAuthStringMaxLength
, MAX_ISCSI_NODENAMELEN
));
1645 (void) strlcpy(lsm
->icl_auth
.ca_tgt_chapuser
,
1646 targetchapuser
, iscsitAuthStringMaxLength
);
1650 * Secrets are stored in base64-encoded format so we need to
1651 * decode them into binary form
1653 if (strcmp(chapsecret
, "") == 0) {
1654 lsm
->icl_auth
.ca_ini_chapsecretlen
= 0;
1656 if (iscsi_base64_str_to_binary(chapsecret
,
1657 strnlen(chapsecret
, iscsitAuthStringMaxLength
),
1658 lsm
->icl_auth
.ca_ini_chapsecret
, iscsitAuthStringMaxLength
,
1659 &lsm
->icl_auth
.ca_ini_chapsecretlen
) != 0) {
1660 cmn_err(CE_WARN
, "Corrupted CHAP secret"
1661 " for initiator %s", lsm
->icl_initiator_name
);
1662 lsm
->icl_auth
.ca_ini_chapsecretlen
= 0;
1665 if (strcmp(targetchapsecret
, "") == 0) {
1666 lsm
->icl_auth
.ca_tgt_chapsecretlen
= 0;
1668 if (iscsi_base64_str_to_binary(targetchapsecret
,
1669 strnlen(targetchapsecret
, iscsitAuthStringMaxLength
),
1670 lsm
->icl_auth
.ca_tgt_chapsecret
, iscsitAuthStringMaxLength
,
1671 &lsm
->icl_auth
.ca_tgt_chapsecretlen
) != 0) {
1672 cmn_err(CE_WARN
, "Corrupted CHAP secret"
1673 " for target %s", lsm
->icl_target_name
);
1674 lsm
->icl_auth
.ca_tgt_chapsecretlen
= 0;
1677 if (strcmp(radiussecret
, "") == 0) {
1678 lsm
->icl_auth
.ca_radius_secretlen
= 0;
1680 if (iscsi_base64_str_to_binary(radiussecret
,
1681 strnlen(radiussecret
, iscsitAuthStringMaxLength
),
1682 lsm
->icl_auth
.ca_radius_secret
, iscsitAuthStringMaxLength
,
1683 &lsm
->icl_auth
.ca_radius_secretlen
) != 0) {
1684 cmn_err(CE_WARN
, "Corrupted RADIUS secret");
1685 lsm
->icl_auth
.ca_radius_secretlen
= 0;
1692 (void) strlcpy(lsm
->icl_auth
.ca_tgt_alias
, targetalias
,
1693 MAX_ISCSI_NODENAMELEN
);
1696 * Now that authentication parameters are setup, validate the parameters
1697 * against the authentication mode
1698 * Decode RADIUS server value int lsm->icl_auth.ca_radius_server
1700 if ((strcmp(auth
, PA_AUTH_RADIUS
) == 0) &&
1701 ((lsm
->icl_auth
.ca_radius_secretlen
== 0) ||
1702 (strcmp(radiusserver
, "") == 0) ||
1703 it_common_convert_sa(radiusserver
,
1704 &lsm
->icl_auth
.ca_radius_server
,
1705 DEFAULT_RADIUS_PORT
) == NULL
)) {
1706 cmn_err(CE_WARN
, "RADIUS authentication selected "
1707 "for target %s but RADIUS parameters are not "
1708 "configured.", lsm
->icl_target_name
);
1709 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_TARGET_ERR
,
1710 ISCSI_LOGIN_STATUS_TARGET_ERROR
);
1711 idmrc
= IDM_STATUS_FAIL
;
1712 } else if ((strcmp(auth
, PA_AUTH_CHAP
) == 0) &&
1713 (lsm
->icl_auth
.ca_ini_chapsecretlen
== 0)) {
1714 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1715 ISCSI_LOGIN_STATUS_AUTH_FAILED
);
1716 idmrc
= IDM_STATUS_FAIL
;
1719 ISCSIT_GLOBAL_UNLOCK();
1726 login_sm_session_register(iscsit_conn_t
*ict
)
1728 iscsit_sess_t
*ist
= ict
->ict_sess
;
1729 stmf_scsi_session_t
*ss
;
1730 iscsi_transport_id_t
*iscsi_tptid
;
1731 uint16_t ident_len
, adn_len
, tptid_sz
;
1734 * Hold target mutex until we have finished registering with STMF
1736 mutex_enter(&ist
->ist_tgt
->target_mutex
);
1737 if (ist
->ist_tgt
->target_state
!= TS_STMF_ONLINE
) {
1738 mutex_exit(&ist
->ist_tgt
->target_mutex
);
1739 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_INITIATOR_ERR
,
1740 ISCSI_LOGIN_STATUS_TGT_REMOVED
);
1741 return (IDM_STATUS_FAIL
);
1744 ss
= stmf_alloc(STMF_STRUCT_SCSI_SESSION
, 0,
1747 mutex_exit(&ist
->ist_tgt
->target_mutex
);
1748 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_TARGET_ERR
,
1749 ISCSI_LOGIN_STATUS_NO_RESOURCES
);
1750 return (IDM_STATUS_FAIL
);
1753 ident_len
= strlen(ist
->ist_initiator_name
) + 1;
1754 ss
->ss_rport_id
= kmem_zalloc(sizeof (scsi_devid_desc_t
) +
1755 ident_len
, KM_SLEEP
);
1756 (void) strcpy((char *)ss
->ss_rport_id
->ident
, ist
->ist_initiator_name
);
1757 ss
->ss_rport_id
->ident_length
= ident_len
- 1;
1758 ss
->ss_rport_id
->protocol_id
= PROTOCOL_iSCSI
;
1759 ss
->ss_rport_id
->piv
= 1;
1760 ss
->ss_rport_id
->code_set
= CODE_SET_ASCII
;
1761 ss
->ss_rport_id
->association
= ID_IS_TARGET_PORT
;
1763 /* adn_len should be 4 byte aligned, SPC3 rev 23, section 7.54.6 */
1764 adn_len
= (ident_len
+ 3) & ~ 3;
1765 tptid_sz
= sizeof (iscsi_transport_id_t
) - 1 + adn_len
;
1766 ss
->ss_rport
= stmf_remote_port_alloc(tptid_sz
);
1767 ss
->ss_rport
->rport_tptid
->protocol_id
= PROTOCOL_iSCSI
;
1768 ss
->ss_rport
->rport_tptid
->format_code
= 0;
1769 iscsi_tptid
= (iscsi_transport_id_t
*)ss
->ss_rport
->rport_tptid
;
1770 SCSI_WRITE16(&iscsi_tptid
->add_len
, adn_len
);
1771 (void) strlcpy((char *)iscsi_tptid
->iscsi_name
,
1772 ist
->ist_initiator_name
, ident_len
);
1774 ss
->ss_lport
= ist
->ist_lport
;
1776 if (stmf_register_scsi_session(ict
->ict_sess
->ist_lport
, ss
) !=
1778 mutex_exit(&ist
->ist_tgt
->target_mutex
);
1779 kmem_free(ss
->ss_rport_id
,
1780 sizeof (scsi_devid_desc_t
) +
1781 strlen(ist
->ist_initiator_name
) + 1);
1782 stmf_remote_port_free(ss
->ss_rport
);
1784 SET_LOGIN_ERROR(ict
, ISCSI_STATUS_CLASS_TARGET_ERR
,
1785 ISCSI_LOGIN_STATUS_TARGET_ERROR
);
1786 return (IDM_STATUS_FAIL
);
1789 ss
->ss_port_private
= ict
->ict_sess
;
1790 ict
->ict_sess
->ist_stmf_sess
= ss
;
1791 mutex_exit(&ist
->ist_tgt
->target_mutex
);
1793 return (IDM_STATUS_SUCCESS
);
1798 login_sm_req_pdu_check(iscsit_conn_t
*ict
, idm_pdu_t
*pdu
)
1801 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1802 iscsi_login_hdr_t
*lh
= (iscsi_login_hdr_t
*)pdu
->isp_hdr
;
1803 iscsi_login_rsp_hdr_t
*lh_resp
= lsm
->icl_login_resp_tmpl
;
1808 csg_req
= ISCSI_LOGIN_CURRENT_STAGE(lh
->flags
);
1810 case ISCSI_SECURITY_NEGOTIATION_STAGE
:
1811 case ISCSI_OP_PARMS_NEGOTIATION_STAGE
:
1812 if ((csg_req
!= lsm
->icl_login_csg
) &&
1813 (lsm
->icl_login_state
!= ILS_LOGIN_INIT
)) {
1815 * Inappropriate CSG change. Initiator can only
1816 * change CSG after we've responded with the
1817 * transit bit set. If we had responded with
1818 * a CSG change previous we would have updated
1821 * The exception is when we are in ILS_LOGIN_INIT
1822 * state since we haven't determined our initial
1825 goto pdu_check_fail
;
1828 case ISCSI_FULL_FEATURE_PHASE
:
1830 goto pdu_check_fail
;
1834 * If this is the first login PDU for a new connection then
1835 * the session will be NULL.
1837 if (ict
->ict_sess
!= NULL
) {
1839 * We've already created a session on a previous PDU. Make
1840 * sure this PDU is consistent with what we've already seen
1842 if ((ict
->ict_cid
!= ntohs(lh
->cid
)) ||
1843 (bcmp(ict
->ict_sess
->ist_isid
, lh
->isid
,
1844 ISCSI_ISID_LEN
) != 0)) {
1845 goto pdu_check_fail
;
1850 * Make sure we are compatible with the version range
1852 #if (ISCSIT_MAX_VERSION > 0)
1853 if ((lh
->min_version
> ISCSIT_MAX_VERSION
) ||
1854 (lh
->max_version
< ISCSIT_MIN_VERSION
)) {
1855 goto pdu_check_fail
;
1860 * Just in case the initiator changes things up on us along the way
1861 * check against our active_version -- we can't change the active
1862 * version and the initiator is not *supposed* to change its
1863 * min_version and max_version values so this should never happen.
1864 * Of course we only do this if the response header template has
1867 if ((lh_resp
->opcode
== ISCSI_OP_LOGIN_RSP
) && /* header valid */
1868 ((lh
->min_version
> lh_resp
->active_version
) ||
1869 (lh
->max_version
< lh_resp
->active_version
))) {
1870 goto pdu_check_fail
;
1873 return (IDM_STATUS_SUCCESS
);
1876 return (IDM_STATUS_FAIL
);
1880 login_sm_process_nvlist(iscsit_conn_t
*ict
)
1882 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1886 nvpair_t
*negotiated_nvp
;
1888 uint8_t error_class
;
1889 uint8_t error_detail
;
1890 idm_status_t idm_status
;
1892 error_class
= ISCSI_STATUS_CLASS_SUCCESS
;
1893 error_detail
= ISCSI_LOGIN_STATUS_ACCEPT
;
1895 /* First, request that the transport process the list */
1896 kvrc
= idm_negotiate_key_values(ict
->ict_ic
, lsm
->icl_request_nvlist
,
1897 lsm
->icl_response_nvlist
, lsm
->icl_negotiated_values
);
1898 idm_kvstat_to_error(kvrc
, &error_class
, &error_detail
);
1899 if (error_class
!= ISCSI_STATUS_CLASS_SUCCESS
) {
1900 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
1901 idm_status
= IDM_STATUS_FAIL
;
1902 return (idm_status
);
1905 /* Ensure we clear transit bit if the transport layer has countered */
1906 if (kvrc
== KV_HANDLED_NO_TRANSIT
) {
1907 lsm
->icl_login_transit
= B_FALSE
;
1910 /* Prepend the declarative params */
1911 if (!ict
->ict_op
.op_declarative_params_set
&&
1912 lsm
->icl_login_csg
== ISCSI_OP_PARMS_NEGOTIATION_STAGE
) {
1913 if (iscsit_add_declarative_keys(ict
) != IDM_STATUS_SUCCESS
) {
1914 idm_status
= IDM_STATUS_FAIL
;
1915 return (idm_status
);
1917 ict
->ict_op
.op_declarative_params_set
= B_TRUE
;
1920 /* Now, move on and process the rest of the pairs */
1921 nvp
= nvlist_next_nvpair(lsm
->icl_request_nvlist
, NULL
);
1922 while (nvp
!= NULL
) {
1923 next_nvp
= nvlist_next_nvpair(lsm
->icl_request_nvlist
, nvp
);
1924 nvp_name
= nvpair_name(nvp
);
1926 * If we've already agreed upon a value then make sure this
1927 * is not attempting to change that value. From RFC3270
1930 * "Neither the initiator nor the target should attempt to
1931 * declare or negotiate a parameter more than once during
1932 * login except for responses to specific keys that
1933 * explicitly allow repeated key declarations (e.g.,
1934 * TargetAddress). An attempt to renegotiate/redeclare
1935 * parameters not specifically allowed MUST be detected
1936 * by the initiator and target. If such an attempt is
1937 * detected by the target, the target MUST respond
1938 * with Login reject (initiator error); ..."
1940 if (nvlist_lookup_nvpair(lsm
->icl_negotiated_values
,
1941 nvp_name
, &negotiated_nvp
) == 0) {
1944 kvrc
= iscsit_handle_key(ict
, nvp
, nvp_name
);
1947 idm_kvstat_to_error(kvrc
, &error_class
, &error_detail
);
1948 if (error_class
!= ISCSI_STATUS_CLASS_SUCCESS
) {
1955 if (error_class
== ISCSI_STATUS_CLASS_SUCCESS
) {
1956 idm_status
= IDM_STATUS_SUCCESS
;
1958 /* supply login class/detail for login errors */
1959 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
1960 idm_status
= IDM_STATUS_FAIL
;
1963 return (idm_status
);
1967 login_sm_check_security(iscsit_conn_t
*ict
)
1969 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
1970 conn_auth_t
*auth
= &lsm
->icl_auth
;
1971 iscsit_auth_method_t
*am_list
= &auth
->ca_method_valid_list
[0];
1973 uint8_t error_class
;
1974 uint8_t error_detail
;
1975 idm_status_t idm_status
;
1977 error_class
= ISCSI_STATUS_CLASS_SUCCESS
;
1978 error_detail
= ISCSI_LOGIN_STATUS_ACCEPT
;
1980 /* Check authentication status. */
1981 if (lsm
->icl_login_csg
== ISCSI_SECURITY_NEGOTIATION_STAGE
) {
1983 * We should have some authentication key/value pair(s)
1984 * received from initiator and the authentication phase
1985 * has been shifted when the key/value pair(s) are being
1986 * handled in the previous call iscsit_handle_security_key.
1987 * Now it turns to target to check the authentication phase
1988 * and shift it after taking some authentication action.
1990 kvrc
= iscsit_reply_security_key(ict
);
1991 idm_kvstat_to_error(kvrc
, &error_class
, &error_detail
);
1992 } else if (!ict
->ict_login_sm
.icl_auth_pass
) {
1994 * Check to see if the target allows initiators to bypass the
1995 * security check. If the target is configured to require
1996 * authentication, we reject the connection.
1998 if (am_list
[0] == AM_NONE
|| am_list
[0] == 0) {
1999 ict
->ict_login_sm
.icl_auth_pass
= 1;
2001 error_class
= ISCSI_STATUS_CLASS_INITIATOR_ERR
;
2002 error_detail
= ISCSI_LOGIN_STATUS_AUTH_FAILED
;
2006 if (error_class
== ISCSI_STATUS_CLASS_SUCCESS
) {
2007 idm_status
= IDM_STATUS_SUCCESS
;
2009 /* supply login class/detail for login errors */
2010 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
2011 idm_status
= IDM_STATUS_FAIL
;
2014 return (idm_status
);
2018 login_sm_build_login_response(iscsit_conn_t
*ict
)
2020 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2021 iscsi_login_rsp_hdr_t
*lh
;
2022 int transit
, text_transit
= 1;
2023 idm_pdu_t
*login_resp
;
2026 * Create a response PDU and fill it with as much of
2027 * the response text that will fit.
2030 if (lsm
->icl_login_resp_itb
) {
2031 /* allocate a pdu with space for text */
2032 login_resp
= idm_pdu_alloc(sizeof (iscsi_hdr_t
),
2033 ISCSI_DEFAULT_MAX_RECV_SEG_LEN
);
2034 /* copy a chunk of text into the pdu */
2035 lsm
->icl_login_resp_buf
= idm_pdu_init_text_data(
2036 login_resp
, lsm
->icl_login_resp_itb
,
2037 ISCSI_DEFAULT_MAX_RECV_SEG_LEN
,
2038 lsm
->icl_login_resp_buf
, &text_transit
);
2040 /* text buf has been consumed */
2041 idm_itextbuf_free(lsm
->icl_login_resp_itb
);
2042 lsm
->icl_login_resp_itb
= NULL
;
2043 lsm
->icl_login_resp_buf
= NULL
;
2046 /* allocate a pdu for just a header */
2047 login_resp
= idm_pdu_alloc(sizeof (iscsi_hdr_t
), 0);
2049 /* finish initializing the pdu */
2050 idm_pdu_init(login_resp
,
2051 ict
->ict_ic
, ict
, login_resp_complete_cb
);
2052 login_resp
->isp_flags
|= IDM_PDU_LOGIN_TX
;
2055 * Use the BHS header values from the response template
2057 bcopy(lsm
->icl_login_resp_tmpl
,
2058 login_resp
->isp_hdr
, sizeof (iscsi_login_rsp_hdr_t
));
2060 lh
= (iscsi_login_rsp_hdr_t
*)login_resp
->isp_hdr
;
2062 /* Set error class/detail */
2063 lh
->status_class
= lsm
->icl_login_resp_err_class
;
2064 lh
->status_detail
= lsm
->icl_login_resp_err_detail
;
2065 /* Set CSG, NSG and Transit */
2067 lh
->flags
|= lsm
->icl_login_csg
<< 2;
2070 if (lh
->status_class
== ISCSI_STATUS_CLASS_SUCCESS
) {
2071 if (lsm
->icl_login_transit
&&
2072 lsm
->icl_auth_pass
!= 0) {
2078 * inititalize the text data
2080 if (transit
== 1 && text_transit
== 1) {
2081 lh
->flags
|= lsm
->icl_login_nsg
;
2082 lsm
->icl_login_csg
= lsm
->icl_login_nsg
;
2083 lh
->flags
|= ISCSI_FLAG_LOGIN_TRANSIT
;
2085 lh
->flags
&= ~ISCSI_FLAG_LOGIN_TRANSIT
;
2088 /* If we are transitioning to FFP then set TSIH */
2089 if (transit
&& (lh
->flags
& ISCSI_FLAG_LOGIN_TRANSIT
) &&
2090 lsm
->icl_login_csg
== ISCSI_FULL_FEATURE_PHASE
) {
2091 lh
->tsid
= htons(ict
->ict_sess
->ist_tsih
);
2094 login_resp
->isp_data
= 0;
2095 login_resp
->isp_datalen
= 0;
2097 return (login_resp
);
2101 iscsit_handle_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
, char *nvp_name
)
2103 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2105 const idm_kv_xlate_t
*ikvx
;
2107 ikvx
= idm_lookup_kv_xlate(nvp_name
, strlen(nvp_name
));
2108 if (ikvx
->ik_key_id
== KI_MAX_KEY
) {
2110 * Any key not understood by the acceptor may be igonred
2111 * by the acceptor without affecting the basic function.
2112 * However, the answer for a key not understood MUST be
2113 * key=NotUnderstood.
2115 kvrc
= iscsit_reply_string(ict
, nvp_name
,
2116 ISCSI_TEXT_NOTUNDERSTOOD
);
2118 kvrc
= iscsit_handle_common_key(ict
, nvp
, ikvx
);
2119 if (kvrc
== KV_UNHANDLED
) {
2120 switch (lsm
->icl_login_csg
) {
2121 case ISCSI_SECURITY_NEGOTIATION_STAGE
:
2122 kvrc
= iscsit_handle_security_key(
2125 case ISCSI_OP_PARMS_NEGOTIATION_STAGE
:
2126 kvrc
= iscsit_handle_operational_key(
2129 case ISCSI_FULL_FEATURE_PHASE
:
2131 /* What are we doing here? */
2133 kvrc
= KV_UNHANDLED
;
2142 iscsit_handle_common_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
2143 const idm_kv_xlate_t
*ikvx
)
2145 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2150 switch (ikvx
->ik_key_id
) {
2151 case KI_INITIATOR_NAME
:
2152 case KI_INITIATOR_ALIAS
:
2153 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
, nvp
);
2154 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2156 case KI_TARGET_NAME
:
2157 /* We'll validate the target during login_sm_session_bind() */
2158 nvrc
= nvpair_value_string(nvp
, &string_val
);
2159 ASSERT(nvrc
== 0); /* We built this nvlist */
2161 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
, nvp
);
2162 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2164 case KI_TARGET_ALIAS
:
2165 case KI_TARGET_ADDRESS
:
2166 case KI_TARGET_PORTAL_GROUP_TAG
:
2167 kvrc
= KV_TARGET_ONLY
; /* Only the target can declare this */
2169 case KI_SESSION_TYPE
:
2171 * If we don't receive this key on the initial login
2172 * we assume this is a normal session.
2174 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
, nvp
);
2175 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2176 nvrc
= nvpair_value_string(nvp
, &string_val
);
2177 ASSERT(nvrc
== 0); /* We built this nvlist */
2178 ict
->ict_op
.op_discovery_session
=
2179 strcmp(string_val
, "Discovery") == 0 ? B_TRUE
: B_FALSE
;
2183 * This is not really an error but we should
2184 * leave this nvpair on the list since we
2185 * didn't do anything with it. Either
2186 * the security or operational phase
2187 * handling functions should process it.
2189 kvrc
= KV_UNHANDLED
;
2197 iscsit_handle_security_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
2198 const idm_kv_xlate_t
*ikvx
)
2200 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2201 iscsit_auth_client_t
*client
= &lsm
->icl_auth_client
;
2202 iscsikey_id_t kv_id
;
2204 iscsit_auth_handler_t handler
;
2207 * After all of security keys are handled, this function will
2208 * be called again to verify current authentication status
2209 * and perform some actual authentication work. At this time,
2210 * the nvp and ikvx will be passed in as NULLs.
2213 kv_id
= ikvx
->ik_key_id
;
2218 handler
= iscsit_auth_get_handler(client
, kv_id
);
2220 kvrc
= handler(ict
, nvp
, ikvx
);
2222 kvrc
= KV_UNHANDLED
; /* invalid request */
2229 iscsit_reply_security_key(iscsit_conn_t
*ict
)
2231 return (iscsit_handle_security_key(ict
, NULL
, NULL
));
2235 iscsit_handle_operational_key(iscsit_conn_t
*ict
, nvpair_t
*nvp
,
2236 const idm_kv_xlate_t
*ikvx
)
2238 kv_status_t kvrc
= KV_UNHANDLED
;
2244 * Retrieve values. All value lookups are expected to succeed
2245 * since we build the nvlist while decoding the text buffer. This
2246 * step is intended to eliminate some duplication of code (for example
2247 * we only need to code the numerical value lookup once). We will
2248 * handle the values (if necessary) below.
2250 switch (ikvx
->ik_key_id
) {
2252 case KI_HEADER_DIGEST
:
2253 case KI_DATA_DIGEST
:
2256 case KI_INITIAL_R2T
:
2257 case KI_IMMEDIATE_DATA
:
2258 case KI_DATA_PDU_IN_ORDER
:
2259 case KI_DATA_SEQUENCE_IN_ORDER
:
2262 nvrc
= nvpair_value_boolean_value(nvp
, &bool_val
);
2263 ASSERT(nvrc
== 0); /* We built this nvlist */
2266 case KI_MAX_CONNECTIONS
:
2267 case KI_MAX_RECV_DATA_SEGMENT_LENGTH
:
2268 case KI_MAX_BURST_LENGTH
:
2269 case KI_FIRST_BURST_LENGTH
:
2270 case KI_DEFAULT_TIME_2_WAIT
:
2271 case KI_DEFAULT_TIME_2_RETAIN
:
2272 case KI_MAX_OUTSTANDING_R2T
:
2273 case KI_ERROR_RECOVERY_LEVEL
:
2274 nvrc
= nvpair_value_uint64(nvp
, &num_val
);
2278 case KI_OFMARKERINT
:
2279 case KI_IFMARKERINT
:
2286 * Now handle the values according to the key name. Sometimes we
2287 * don't care what the value is -- in that case we just add the nvpair
2288 * to the negotiated values list.
2290 switch (ikvx
->ik_key_id
) {
2291 case KI_HEADER_DIGEST
:
2292 kvrc
= iscsit_handle_digest(ict
, nvp
, ikvx
);
2294 case KI_DATA_DIGEST
:
2295 kvrc
= iscsit_handle_digest(ict
, nvp
, ikvx
);
2297 case KI_INITIAL_R2T
:
2298 /* We *require* INITIAL_R2T=yes */
2299 kvrc
= iscsit_handle_boolean(ict
, nvp
, bool_val
, ikvx
,
2302 case KI_IMMEDIATE_DATA
:
2303 kvrc
= iscsit_handle_boolean(ict
, nvp
, bool_val
, ikvx
,
2306 case KI_DATA_PDU_IN_ORDER
:
2307 kvrc
= iscsit_handle_boolean(ict
, nvp
, bool_val
, ikvx
,
2310 case KI_DATA_SEQUENCE_IN_ORDER
:
2311 /* We allow any value for DATA_SEQUENCE_IN_ORDER */
2312 kvrc
= iscsit_handle_boolean(ict
, nvp
, bool_val
, ikvx
,
2317 /* We don't support markers */
2318 kvrc
= iscsit_handle_boolean(ict
, nvp
, bool_val
, ikvx
,
2321 case KI_MAX_CONNECTIONS
:
2322 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2323 ISCSI_MIN_CONNECTIONS
,
2324 ISCSI_MAX_CONNECTIONS
,
2325 ISCSIT_MAX_CONNECTIONS
);
2327 /* this is a declartive param */
2328 case KI_MAX_RECV_DATA_SEGMENT_LENGTH
:
2329 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2330 ISCSI_MIN_RECV_DATA_SEGMENT_LENGTH
,
2331 ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH
,
2332 ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH
);
2334 case KI_MAX_BURST_LENGTH
:
2335 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2336 ISCSI_MIN_MAX_BURST_LENGTH
,
2337 ISCSI_MAX_BURST_LENGTH
,
2338 ISCSIT_MAX_BURST_LENGTH
);
2340 case KI_FIRST_BURST_LENGTH
:
2341 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2342 ISCSI_MIN_FIRST_BURST_LENGTH
,
2343 ISCSI_MAX_FIRST_BURST_LENGTH
,
2344 ISCSIT_MAX_FIRST_BURST_LENGTH
);
2346 case KI_DEFAULT_TIME_2_WAIT
:
2347 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2348 ISCSI_MIN_TIME2WAIT
,
2349 ISCSI_MAX_TIME2WAIT
,
2350 ISCSIT_MAX_TIME2WAIT
);
2352 case KI_DEFAULT_TIME_2_RETAIN
:
2353 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2354 ISCSI_MIN_TIME2RETAIN
,
2355 ISCSI_MAX_TIME2RETAIN
,
2356 ISCSIT_MAX_TIME2RETAIN
);
2358 case KI_MAX_OUTSTANDING_R2T
:
2359 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2360 ISCSI_MIN_MAX_OUTSTANDING_R2T
,
2361 ISCSI_MAX_OUTSTANDING_R2T
,
2362 ISCSIT_MAX_OUTSTANDING_R2T
);
2364 case KI_ERROR_RECOVERY_LEVEL
:
2365 kvrc
= iscsit_handle_numerical(ict
, nvp
, num_val
, ikvx
,
2366 ISCSI_MIN_ERROR_RECOVERY_LEVEL
,
2367 ISCSI_MAX_ERROR_RECOVERY_LEVEL
,
2368 ISCSIT_MAX_ERROR_RECOVERY_LEVEL
);
2370 case KI_OFMARKERINT
:
2371 case KI_IFMARKERINT
:
2372 kvrc
= iscsit_reply_string(ict
, ikvx
->ik_key_name
,
2373 ISCSI_TEXT_IRRELEVANT
);
2376 kvrc
= KV_UNHANDLED
; /* invalid request */
2384 iscsit_reply_numerical(iscsit_conn_t
*ict
,
2385 const char *nvp_name
, const uint64_t value
)
2387 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2391 nvrc
= nvlist_add_uint64(lsm
->icl_response_nvlist
,
2393 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2399 iscsit_reply_string(iscsit_conn_t
*ict
,
2400 const char *nvp_name
, const char *text
)
2402 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2406 nvrc
= nvlist_add_string(lsm
->icl_response_nvlist
,
2408 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2414 iscsit_handle_digest(iscsit_conn_t
*ict
, nvpair_t
*choices
,
2415 const idm_kv_xlate_t
*ikvx
)
2417 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2418 kv_status_t kvrc
= KV_VALUE_ERROR
;
2420 nvpair_t
*digest_choice
;
2421 char *digest_choice_string
;
2424 * Need to add persistent config here if we want users to allow
2425 * disabling of digests on the target side. You could argue that
2426 * this makes things too complicated... just let the initiator state
2427 * what it wants and we'll take it. For now that's exactly what
2430 * Basic digest negotiation happens here at iSCSI level. IDM
2431 * can override this during negotiate_key_values phase to
2432 * decline to set up any digest processing.
2434 digest_choice
= idm_get_next_listvalue(choices
, NULL
);
2437 * Loop through all choices. As soon as we find a choice
2438 * that we support add the value to our negotiated values list
2439 * and respond with that value in the login response.
2441 while (digest_choice
!= NULL
) {
2442 nvrc
= nvpair_value_string(digest_choice
,
2443 &digest_choice_string
);
2446 if ((strcasecmp(digest_choice_string
, "crc32c") == 0) ||
2447 (strcasecmp(digest_choice_string
, "none") == 0)) {
2448 /* Add to negotiated values list */
2449 nvrc
= nvlist_add_string(lsm
->icl_negotiated_values
,
2450 ikvx
->ik_key_name
, digest_choice_string
);
2451 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2453 /* Add to login response list */
2454 nvrc
= nvlist_add_string(
2455 lsm
->icl_response_nvlist
,
2456 ikvx
->ik_key_name
, digest_choice_string
);
2457 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2461 digest_choice
= idm_get_next_listvalue(choices
,
2465 if (digest_choice
== NULL
)
2466 kvrc
= KV_VALUE_ERROR
;
2472 iscsit_handle_boolean(iscsit_conn_t
*ict
, nvpair_t
*nvp
, boolean_t value
,
2473 const idm_kv_xlate_t
*ikvx
, boolean_t iscsit_value
)
2475 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2479 if (ikvx
->ik_declarative
) {
2480 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
, nvp
);
2482 if (value
!= iscsit_value
) {
2483 /* Respond back to initiator with our value */
2484 value
= iscsit_value
;
2485 nvrc
= nvlist_add_boolean_value(
2486 lsm
->icl_negotiated_values
,
2487 ikvx
->ik_key_name
, value
);
2488 lsm
->icl_login_transit
= B_FALSE
;
2490 /* Add this to our negotiated values */
2491 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
,
2495 /* Response of Simple-value Negotiation */
2497 nvrc
= nvlist_add_boolean_value(
2498 lsm
->icl_response_nvlist
, ikvx
->ik_key_name
, value
);
2502 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2508 iscsit_handle_numerical(iscsit_conn_t
*ict
, nvpair_t
*nvp
, uint64_t value
,
2509 const idm_kv_xlate_t
*ikvx
,
2510 uint64_t iscsi_min_value
, uint64_t iscsi_max_value
,
2511 uint64_t iscsit_max_value
)
2513 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2517 /* Validate against standard */
2518 if ((value
< iscsi_min_value
) || (value
> iscsi_max_value
)) {
2519 kvrc
= KV_VALUE_ERROR
;
2520 } else if (ikvx
->ik_declarative
) {
2521 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
, nvp
);
2522 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2524 if (value
> iscsit_max_value
) {
2525 /* Respond back to initiator with our value */
2526 value
= iscsit_max_value
;
2527 nvrc
= nvlist_add_uint64(lsm
->icl_negotiated_values
,
2528 ikvx
->ik_key_name
, value
);
2529 lsm
->icl_login_transit
= B_FALSE
;
2531 /* Add this to our negotiated values */
2532 nvrc
= nvlist_add_nvpair(lsm
->icl_negotiated_values
,
2536 /* Response of Simple-value Negotiation */
2538 nvrc
= nvlist_add_uint64(lsm
->icl_response_nvlist
,
2539 ikvx
->ik_key_name
, value
);
2541 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2549 iscsit_process_negotiated_values(iscsit_conn_t
*ict
)
2551 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2553 boolean_t boolean_val
;
2554 uint64_t uint64_val
;
2557 /* Let the IDM level activate its parameters first */
2558 idm_notice_key_values(ict
->ict_ic
, lsm
->icl_negotiated_values
);
2561 * Initiator alias and target alias
2563 if ((nvrc
= nvlist_lookup_string(lsm
->icl_negotiated_values
,
2564 "InitiatorAlias", &string_val
)) != ENOENT
) {
2566 ict
->ict_sess
->ist_initiator_alias
=
2567 kmem_alloc(strlen(string_val
) + 1, KM_SLEEP
);
2568 (void) strcpy(ict
->ict_sess
->ist_initiator_alias
, string_val
);
2569 if (ict
->ict_sess
->ist_stmf_sess
)
2570 ict
->ict_sess
->ist_stmf_sess
->ss_rport_alias
=
2574 if ((nvrc
= nvlist_lookup_string(lsm
->icl_negotiated_values
,
2575 "TargetAlias", &string_val
)) != ENOENT
) {
2577 ict
->ict_sess
->ist_target_alias
=
2578 kmem_alloc(strlen(string_val
) + 1, KM_SLEEP
);
2579 (void) strcpy(ict
->ict_sess
->ist_target_alias
, string_val
);
2583 * Operational parameters. We process SessionType when it is
2584 * initially received since it is required on the initial login.
2586 if ((nvrc
= nvlist_lookup_boolean_value(lsm
->icl_negotiated_values
,
2587 "InitialR2T", &boolean_val
)) != ENOENT
) {
2589 ict
->ict_op
.op_initial_r2t
= boolean_val
;
2592 if ((nvrc
= nvlist_lookup_boolean_value(lsm
->icl_negotiated_values
,
2593 "ImmediateData", &boolean_val
)) != ENOENT
) {
2595 ict
->ict_op
.op_immed_data
= boolean_val
;
2598 if ((nvrc
= nvlist_lookup_boolean_value(lsm
->icl_negotiated_values
,
2599 "DataPDUInOrder", &boolean_val
)) != ENOENT
) {
2601 ict
->ict_op
.op_data_pdu_in_order
= boolean_val
;
2604 if ((nvrc
= nvlist_lookup_boolean_value(lsm
->icl_negotiated_values
,
2605 "DataSequenceInOrder", &boolean_val
)) != ENOENT
) {
2607 ict
->ict_op
.op_data_sequence_in_order
= boolean_val
;
2610 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2611 "MaxConnections", &uint64_val
)) != ENOENT
) {
2613 ict
->ict_op
.op_max_connections
= uint64_val
;
2616 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2617 "MaxRecvDataSegmentLength", &uint64_val
)) != ENOENT
) {
2619 ict
->ict_op
.op_max_recv_data_segment_length
= uint64_val
;
2622 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2623 "MaxBurstLength", &uint64_val
)) != ENOENT
) {
2625 ict
->ict_op
.op_max_burst_length
= uint64_val
;
2628 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2629 "FirstBurstLength", &uint64_val
)) != ENOENT
) {
2631 ict
->ict_op
.op_first_burst_length
= uint64_val
;
2634 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2635 "DefaultTime2Wait", &uint64_val
)) != ENOENT
) {
2637 ict
->ict_op
.op_default_time_2_wait
= uint64_val
;
2640 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2641 "DefaultTime2Retain", &uint64_val
)) != ENOENT
) {
2643 ict
->ict_op
.op_default_time_2_retain
= uint64_val
;
2646 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2647 "MaxOutstandingR2T", &uint64_val
)) != ENOENT
) {
2649 ict
->ict_op
.op_max_outstanding_r2t
= uint64_val
;
2652 if ((nvrc
= nvlist_lookup_uint64(lsm
->icl_negotiated_values
,
2653 "ErrorRecoveryLevel", &uint64_val
)) != ENOENT
) {
2655 ict
->ict_op
.op_error_recovery_level
= uint64_val
;
2660 iscsit_add_declarative_keys(iscsit_conn_t
*ict
)
2662 nvlist_t
*cfg_nv
= NULL
;
2665 iscsit_conn_login_t
*lsm
= &ict
->ict_login_sm
;
2666 uint8_t error_class
;
2667 uint8_t error_detail
;
2668 idm_status_t idm_status
;
2670 if ((nvrc
= nvlist_alloc(&cfg_nv
, NV_UNIQUE_NAME
, KM_NOSLEEP
)) != 0) {
2671 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2674 if ((nvrc
= nvlist_add_uint64(cfg_nv
, "MaxRecvDataSegmentLength",
2675 max_dataseglen_target
)) != 0) {
2676 kvrc
= idm_nvstat_to_kvstat(nvrc
);
2680 kvrc
= idm_declare_key_values(ict
->ict_ic
, cfg_nv
,
2681 lsm
->icl_response_nvlist
);
2683 nvlist_free(cfg_nv
);
2685 idm_kvstat_to_error(kvrc
, &error_class
, &error_detail
);
2686 if (error_class
== ISCSI_STATUS_CLASS_SUCCESS
) {
2687 idm_status
= IDM_STATUS_SUCCESS
;
2689 SET_LOGIN_ERROR(ict
, error_class
, error_detail
);
2690 idm_status
= IDM_STATUS_FAIL
;
2692 return (idm_status
);