/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2016 Nexenta Systems, Inc.
*/
#include <sys/sysmacros.h>
#include <sys/stmf_ioctl.h>
#define ISCSIT_LOGIN_SM_STRINGS
#include "iscsit.h"
#include "iscsit_auth.h"
typedef struct {
#ifndef TRUE
#endif
#ifndef FALSE
#endif
static void
login_sm_complete(void *ict_void);
static void
static void
static void
static void
static void
static void
static void
static void
static void
static void
static void
static idm_status_t
static boolean_t
static void
static void
static void
static idm_status_t
static idm_status_t
static idm_status_t
static idm_pdu_t *
static void
static idm_status_t
static idm_status_t
static idm_status_t
static idm_status_t
static kv_status_t
static kv_status_t
const idm_kv_xlate_t *ikvx);
static kv_status_t
const idm_kv_xlate_t *ikvx);
static kv_status_t
static kv_status_t
const idm_kv_xlate_t *ikvx);
static kv_status_t
static kv_status_t
static kv_status_t
const idm_kv_xlate_t *ikvx);
static kv_status_t
static kv_status_t
const idm_kv_xlate_t *ikvx,
static void
static void
static idm_status_t
static char *
/*
* global mutex defined in iscsit.c to enforce
* login_sm_session_bind as a critical section
*/
extern kmutex_t login_sm_session_mutex;
{
KM_SLEEP);
/*
* Hold connection until the login state machine completes
*/
/*
* Pre-allocating a login response PDU means we will always be
* able to respond to a login request -- even if we can't allocate
* a data buffer to hold the text responses we can at least send
* a login failure.
*/
KM_SLEEP);
/*
* Initialize operational parameters to default values. Anything
* we don't specifically negotiate stays at the default.
*/
return (IDM_STATUS_SUCCESS);
}
static void
{
/*
* Check that this is a login pdu
*/
if ((status != IDM_STATUS_SUCCESS) ||
/*
* Transport or login error occurred.
*/
}
}
void
{
/* clean up the login response idm text buffer */
}
}
void
{
/*
* This is a bit ugly but if we're already in ILS_LOGIN_ERROR
* or ILS_LOGIN_DONE then just drop any additional events. They
* won't change the state and it's possible we've already called
* iscsit_login_sm_fini in which case the mutex is destroyed.
*/
return;
}
void
{
/*
* Use the icl_busy flag to keep the state machine single threaded.
* This also serves as recursion avoidance since this flag will
* always be set if we call login_sm_event from within the
* state machine code.
*/
/*
* If the lsm is in a terminal state, just drain
* any remaining events.
*/
continue;
}
}
/*
* When the state machine reaches ILS_LOGIN_DONE or
* ILS_LOGIN_ERROR state the login process has completed
* and it's time to cleanup. The state machine code will
* mark itself "complete" when this happens.
*
* To protect against spurious events (which shouldn't
* happen) set icl_busy again.
*/
if (lsm->icl_login_complete) {
" Failed to dispatch task");
}
}
}
}
static void
{
/*
* State machine has run to completion, resources
* will be cleaned up when connection is destroyed.
*/
}
static void
{
login_event_ctx_t *, ctx);
(void *)ict,
/* State independent actions */
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/* Perform basic sanity checks on the header */
/*
* If we haven't processed any PDU's yet then use
* this one as a template for the response
*/
return;
}
break;
default:
break;
}
/* State dependent actions */
switch (lsm->icl_login_state) {
case ILS_LOGIN_INIT:
break;
case ILS_LOGIN_WAITING:
break;
case ILS_LOGIN_PROCESSING:
break;
case ILS_LOGIN_RESPONDING:
break;
case ILS_LOGIN_RESPONDED:
break;
case ILS_LOGIN_FFP:
break;
case ILS_LOGIN_DONE:
break;
case ILS_LOGIN_ERROR:
break;
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/*
* This is the first login PDU we've received so use
* it to build the login response template and set our CSG.
*/
/*
* Accumulate all the login PDU's that make up this
* request on a queue.
*/
} else {
}
break;
case ILE_LOGIN_CONN_ERROR:
case ILE_LOGIN_ERROR:
break;
default:
ASSERT(0);
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
} else {
}
break;
case ILE_LOGIN_ERROR:
break;
case ILE_LOGIN_RESP_COMPLETE:
break;
default:
ASSERT(0);
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RESP_READY:
break;
case ILE_LOGIN_RCV:
/*FALLTHROUGH*/
case ILE_LOGIN_CONN_ERROR:
case ILE_LOGIN_ERROR:
break;
default:
ASSERT(0);
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/*
* We should only be in "responding" state if we have not
* sent the last PDU of a multi-PDU login response sequence.
* In that case we expect this received PDU to be an
* acknowledgement from the initiator (login PDU with C
* bit cleared and no data). If it's the acknowledgement
* we are expecting then we send the next PDU in the login
* response sequence. Otherwise it's a protocol error and
* the login fails.
*/
} else {
}
break;
case ILE_LOGIN_FFP:
break;
case ILE_LOGIN_RESP_COMPLETE:
break;
case ILE_LOGIN_CONN_ERROR:
case ILE_LOGIN_ERROR:
break;
default:
ASSERT(0);
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/*
* Set the CSG, NSG and Transit bits based on the this PDU.
* The CSG already validated in login_sm_req_pdu_check().
* We'll clear the transit bit if we encounter any login
* parameters in the request that required an additional
* login transfer (i.e. no acceptable
* choices in range or we needed to change a boolean
* value from "Yes" to "No").
*/
} else {
}
break;
case ILE_LOGIN_CONN_ERROR:
case ILE_LOGIN_ERROR:
break;
default:
ASSERT(0);
}
}
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RESP_COMPLETE:
break;
case ILE_LOGIN_CONN_ERROR:
case ILE_LOGIN_ERROR:
break;
default:
ASSERT(0);
}
}
/*ARGSUSED*/
static void
{
/* Terminal state, we should get no events */
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/*
* We've already processed everything we're going to
* process. Drop any additional login PDU's.
*/
break;
case ILE_LOGIN_CONN_ERROR:
/* Don't care */
break;
default:
ASSERT(0);
}
}
/*ARGSUSED*/
static void
{
switch (ctx->le_ctx_event) {
case ILE_LOGIN_RCV:
/*
* We've already processed everything we're going to
* process. Drop any additional login PDU's.
*/
break;
case ILE_LOGIN_CONN_ERROR:
/* Don't care */
break;
default:
ASSERT(0);
}
}
static void
{
/*
* Validate new state
*/
switch (lsm->icl_login_state) {
case ILS_LOGIN_WAITING:
/* Do nothing, waiting for more login PDU's */
break;
case ILS_LOGIN_PROCESSING:
/* All login PDU's received, process login request */
break;
case ILS_LOGIN_RESPONDING:
break;
case ILS_LOGIN_RESPONDED:
/* clean up the login response idm text buffer */
}
break;
case ILS_LOGIN_FFP:
break;
case ILS_LOGIN_DONE:
case ILS_LOGIN_ERROR:
/*
* Flag the terminal state for the dispatcher
*/
break;
case ILS_LOGIN_INIT: /* Initial state, can't return */
default:
ASSERT(0);
/*NOTREACHED*/
}
}
/*ARGSUSED*/
static void
{
/*
* allocate the response pdu
*/
/*
* copy the response template into the response pdu
*/
}
/*ARGSUSED*/
static idm_status_t
{
return (IDM_STATUS_FAIL);
}
return (IDM_STATUS_FAIL);
}
return (IDM_STATUS_SUCCESS);
}
static boolean_t
{
return (B_FALSE);
}
return (B_TRUE);
}
static void
{
/*
* First login PDU, this connection should not have a sesssion
* associated.
*/
/*
* Save off TSIH and ISID for later use in finding a session
*/
/*
* We'll need the CID as well
*/
/*
* Set the CSG, NSG and Transit bits based on the first PDU
* in the login sequence. The CSG already validated in
* login_sm_req_pdu_check(). We'll clear the transit bit if
* we encounter any login parameters in the request that
* required an additional login transfer (i.e. no acceptable
* choices in range or we needed to change a boolean
* value from "Yes" to "No").
*/
/*
* Initialize header for login reject response. This will also
* be copied for use as a template for other login responses
*/
/*
* We already validated that we can support one of the initiator's
* versions in login_sm_req_pdu_check().
*/
#if (ISCSIT_MAX_VERSION > 0)
} else {
}
#endif
/*
* StatSn, ExpCmdSn and MaxCmdSn will be set immediately before
* transmission
*/
}
static void
{
/* Make sure this PDU is part of the login phase */
/*
* Fill in header values
*/
/*
* If the login is successful, this login response will contain
* the next StatSN and advance the StatSN for the connection.
*/
}
/*
* The last of a potentially mult-PDU response finished.
*/
NULL);
}
} else {
/*
* If status_class != ISCSI_STATUS_CLASS_SUCCESS then
* StatSN is not valid and we can call idm_pdu_tx instead
* of iscsit_pdu_tx. This is very good thing since in
* some cases of login failure we may not have a session.
* Since iscsit_calc_rspsn grabs the session mutex while
* it is retrieving values for expcmdsn and maxcmdsn this
* would cause a panic.
*
* Since we still want a value for expcmdsn, fill in an
* appropriate value based on the login request before
* login phase.
*/
}
}
static void
{
/*
* First walk all the PDU's that make up this login request
* and compile all the iSCSI key-value pairs into nvlist format.
*/
goto request_fail;
}
KM_NOSLEEP) != 0) {
goto request_fail;
}
/*
* This would be a very good time to make sure we have
* negotiated the required values for the login phase. For
* example we definitely should have defined InitiatorName,
* and Target name regardless of our current login phase.
*/
goto request_fail;
}
/*
* Now setup our session association. This includes
* create a new session or looking up an existing session,
* and if this is not a discovery session then we will
* also register this session with STMF.
*/
goto request_fail;
}
goto request_fail;
}
/*
* Prepend TargetAlias and PortalGroupTag
*/
(void) iscsit_reply_string(ict,
"TargetAlias",
}
(void) iscsit_reply_numerical(ict,
"TargetPortalGroupTag",
}
}
goto request_fail;
}
goto request_fail;
}
/* clean up request_nvlist */
}
/* convert any responses to textbuf form */
if (lsm->icl_response_nvlist) {
/* Still need to send the resp so continue */
}
/* clean up response_nvlist */
}
/* tell the state machine to send the textbuf */
return;
/* clean up request_nvlist and response_nvlist */
}
}
/* Make sure we already set the login error */
}
}
static void
{
}
static idm_status_t
{
int nvrc;
char *string_val;
char *u8_iscsi_name;
/*
* Make sure we received the required information from the initial
* login. Add these declaratives to the negotiated list and
* remove them from the request list as we go. If anything fails,
* the caller will clean-up the nvlists.
*/
/*
* Initiator name
*/
"InitiatorName", &string_val)) != 0) {
goto initial_params_done;
}
if (u8_iscsi_name == NULL)
goto initial_params_done;
if (nvrc != 0)
goto initial_params_done;
"InitiatorName", &string_val)) != 0) {
goto initial_params_done;
}
"InitiatorName", DATA_TYPE_STRING)) != 0) {
goto initial_params_done;
}
/*
* Session type
*/
"SessionType", &string_val);
goto initial_params_done;
}
if (nvrc == 0) {
goto initial_params_done;
}
"SessionType", string_val)) != 0) {
goto initial_params_done;
}
"SessionType", DATA_TYPE_STRING)) != 0) {
goto initial_params_done;
}
}
/*
* Must have either TargetName or SessionType==Discovery
*/
"TargetName", &string_val);
goto initial_params_done;
}
if (nvrc == 0) {
if (u8_iscsi_name == NULL)
goto initial_params_done;
"TargetName", u8_iscsi_name);
if (nvrc != 0)
goto initial_params_done;
"TargetName", &string_val)) != 0) {
goto initial_params_done;
}
"TargetName", DATA_TYPE_STRING)) != 0) {
goto initial_params_done;
}
/*
* Missing target name
*/
goto initial_params_done;
}
/* Sucess */
return (status);
}
/*
* login_sm_session_bind
*
* This function looks at the data from the initial login request
* of a new connection and either looks up and existing session,
* creates a new session, or returns an error. RFC3720 section 5.3.1
* defines these rules:
*
* +------------------------------------------------------------------+
* |ISID | TSIH | CID | Target action |
* +------------------------------------------------------------------+
* |new | non-zero | any | fail the login |
* | | | | ("session does not exist") |
* +------------------------------------------------------------------+
* |new | zero | any | instantiate a new session |
* +------------------------------------------------------------------+
* |existing | zero | any | do session reinstatement |
* | | | | (see section 5.3.5) |
* +------------------------------------------------------------------+
* |existing | non-zero | new | add a new connection to |
* | | existing | | the session |
* +------------------------------------------------------------------+
* |existing | non-zero |existing| do connection reinstatement|
* | | existing | | (see section 5.3.4) |
* +------------------------------------------------------------------+
* |existing | non-zero | any | fail the login |
* | | new | | ("session does not exist") |
* +------------------------------------------------------------------+
*
*/
/*
* Map an <ipv6,port> address to an <ipv4,port> address if possible.
* Returns:
* 1 - success
* 0 - address not mapable
*/
int
{
int ret = 0;
ret = 1;
}
return (ret);
}
static idm_status_t
{
/*
* The multi-threaded execution of binding login sessions to target
* allowed duplicate sessions to tbe created. The addition of the
* global mutex login_sm_session_mutex makes this function single
* threaded to avoid such race conditions. Although this causes
* a small portion of the login to be serialized, it is unlikely
* that there would be numerous simultaneous logins to become a
* performance issue.
*/
/*
* Look up target and then check if there are sessions or connections
* that match this request (see below). Any holds taken on objects
* must be released at the end of the function (let's keep things
* simple).
*
* If target name is set then we should have a corresponding target
* context configured.
*/
/*
* iscsit_tgt_lookup implicitly takes a ref on the target
*/
goto session_bind_error;
} else {
if (IS_DEFAULT_TPGT(tpgt)) {
} else {
/*
* Find the portal group tag for the
* login response.
*/
/*
* Try again if the local address
* was v6 mappable to v4.
*/
}
/*
* Initiator came in on wrong address
*/
goto session_bind_error;
}
/*
* Need to release holds on the portal and
* tpgt after processing is complete.
*/
}
goto session_bind_error;
}
}
}
/*
* Check if there is an existing session matching this ISID. If
* tgt == NULL then we'll look for the session on the global list
* of discovery session. If we find a session then the ISID
* exists.
*/
if (existing_sess != NULL) {
}
/*
* If this is a discovery session, make sure it has appropriate
* parameters.
*/
/* XXX Do we need to check for existing ISID (sess != NULL)? */
goto session_bind_error;
}
/*
* Check the two error conditions from the table.
*
* ISID=new, TSIH=non-zero
*/
/* fail the login */
goto session_bind_error;
}
/* ISID=existing, TSIH=non-zero new */
/* fail the login */
goto session_bind_error;
}
/*
* Handle the remaining table cases in order
*/
if (existing_sess == NULL) {
/* Should have caught this above */
/*
* ISID=new, TSIH=zero --> instantiate a new session
*/
/* Session create may have failed even if it returned a value */
if (error_class != ISCSI_STATUS_CLASS_SUCCESS) {
goto session_bind_error;
}
/*
* If we don't already have an STMF session and this is not
* a discovery session then we need to allocate and register
* one.
*/
if (login_sm_session_register(ict) !=
/* login_sm_session_register sets error codes */
goto session_bind_error;
}
}
} else {
/*
* ISID=existing, TSIH=zero --> Session reinstatement
*/
if (error_class != ISCSI_STATUS_CLASS_SUCCESS) {
goto session_bind_error;
}
/*
* If we don't already have an STMF session and this is
* not a discovery session then we need to allocate and
* register one.
*/
if (login_sm_session_register(ict) !=
/*
* login_sm_session_register sets
* error codes
*/
goto session_bind_error;
}
}
} else {
/*
* The following code covers these two cases:
* ISID=existing, TSIH=non-zero existing, CID=new
* --> add new connection to MC/S session
* ISID=existing, TSIH=non-zero existing, CID=existing
* --> do connection reinstatement
*
* Session continuation uses this path as well
*/
if (existing_ict != NULL) {
/*
* ISID=existing, TSIH=non-zero existing,
* CID=existing --> do connection reinstatement
*/
/*
* Most likely this means the connection
* the initiator is trying to reinstate
* is not in an acceptable state.
*/
goto session_bind_error;
}
}
ict);
}
}
if (existing_sess != NULL)
if (existing_ict != NULL)
return (IDM_STATUS_SUCCESS);
if (existing_sess != NULL)
if (existing_ict != NULL)
/*
* If session bind fails we will fail the login but don't destroy
* the session until later.
*/
return (IDM_STATUS_FAIL);
}
static idm_status_t
{
int i;
/*
* Set authentication method to none for discovery session.
*/
return (idmrc);
}
/*
* Get all the authentication parameters we need -- since we hold
* the global config lock we guarantee that the parameters will
* be consistent with each other.
*/
/* Get Initiator CHAP parameters */
&chapuser);
&chapsecret);
}
/* See if we have a target-specific authentication setting */
&auth);
/* Get target CHAP parameters */
/* Get alias */
}
/* Set authentication method */
i = 0;
/* CHAP authentication using RADIUS server */
/* Local CHAP authentication */
/* No authentication */
}
/*
* node name. If lsm->icl_target_name == NULL then this is
* a discovery session so we don't need to work about the target.
*/
} else {
}
} else {
}
/*
* Secrets are stored in base64-encoded format so we need to
* decode them into binary form
*/
} else {
}
}
} else {
}
}
} else {
}
}
/*
* Set alias
*/
/*
* Now that authentication parameters are setup, validate the parameters
* against the authentication mode
* Decode RADIUS server value int lsm->icl_auth.ca_radius_server
*/
DEFAULT_RADIUS_PORT) == NULL)) {
"for target %s but RADIUS parameters are not "
}
return (idmrc);
}
static idm_status_t
{
/*
* Hold target mutex until we have finished registering with STMF
*/
return (IDM_STATUS_FAIL);
}
0);
return (IDM_STATUS_FAIL);
}
/* adn_len should be 4 byte aligned, SPC3 rev 23, section 7.54.6 */
STMF_SUCCESS) {
sizeof (scsi_devid_desc_t) +
return (IDM_STATUS_FAIL);
}
return (IDM_STATUS_SUCCESS);
}
static idm_status_t
{
/*
* Check CSG
*/
switch (csg_req) {
/*
* Inappropriate CSG change. Initiator can only
* change CSG after we've responded with the
* transit bit set. If we had responded with
* a CSG change previous we would have updated
* our copy of CSG.
*
* The exception is when we are in ILS_LOGIN_INIT
* state since we haven't determined our initial
* CSG value yet.
*/
goto pdu_check_fail;
}
break;
case ISCSI_FULL_FEATURE_PHASE:
default:
goto pdu_check_fail;
}
/*
* If this is the first login PDU for a new connection then
* the session will be NULL.
*/
/*
* We've already created a session on a previous PDU. Make
* sure this PDU is consistent with what we've already seen
*/
ISCSI_ISID_LEN) != 0)) {
goto pdu_check_fail;
}
}
/*
* Make sure we are compatible with the version range
*/
#if (ISCSIT_MAX_VERSION > 0)
goto pdu_check_fail;
}
#endif
/*
* Just in case the initiator changes things up on us along the way
* check against our active_version -- we can't change the active
* version and the initiator is not *supposed* to change its
* min_version and max_version values so this should never happen.
* Of course we only do this if the response header template has
* been built.
*/
goto pdu_check_fail;
}
return (IDM_STATUS_SUCCESS);
return (IDM_STATUS_FAIL);
}
static idm_status_t
{
char *nvp_name;
/* First, request that the transport process the list */
if (error_class != ISCSI_STATUS_CLASS_SUCCESS) {
return (idm_status);
}
/* Ensure we clear transit bit if the transport layer has countered */
if (kvrc == KV_HANDLED_NO_TRANSIT) {
}
/* Prepend the declarative params */
return (idm_status);
}
}
/* Now, move on and process the rest of the pairs */
/*
* If we've already agreed upon a value then make sure this
* is not attempting to change that value. From RFC3270
* section 5.3:
*
* "Neither the initiator nor the target should attempt to
* declare or negotiate a parameter more than once during
* login except for responses to specific keys that
* explicitly allow repeated key declarations (e.g.,
* TargetAddress). An attempt to renegotiate/redeclare
* parameters not specifically allowed MUST be detected
* by the initiator and target. If such an attempt is
* detected by the target, the target MUST respond
* with Login reject (initiator error); ..."
*/
nvp_name, &negotiated_nvp) == 0) {
kvrc = KV_HANDLED;
} else {
}
if (error_class != ISCSI_STATUS_CLASS_SUCCESS) {
break;
}
}
if (error_class == ISCSI_STATUS_CLASS_SUCCESS) {
} else {
}
return (idm_status);
}
static idm_status_t
{
/* Check authentication status. */
/*
* received from initiator and the authentication phase
* handled in the previous call iscsit_handle_security_key.
* Now it turns to target to check the authentication phase
* and shift it after taking some authentication action.
*/
/*
* Check to see if the target allows initiators to bypass the
* security check. If the target is configured to require
* authentication, we reject the connection.
*/
} else {
}
}
if (error_class == ISCSI_STATUS_CLASS_SUCCESS) {
} else {
}
return (idm_status);
}
static idm_pdu_t *
{
/*
* Create a response PDU and fill it with as much of
* the response text that will fit.
*/
if (lsm->icl_login_resp_itb) {
/* allocate a pdu with space for text */
/* copy a chunk of text into the pdu */
if (text_transit) {
/* text buf has been consumed */
}
} else {
/* allocate a pdu for just a header */
}
/* finish initializing the pdu */
/*
* Use the BHS header values from the response template
*/
/* Set CSG, NSG and Transit */
if (lsm->icl_login_transit &&
lsm->icl_auth_pass != 0) {
transit = 1;
} else {
transit = 0;
}
/*
* inititalize the text data
*/
} else {
}
/* If we are transitioning to FFP then set TSIH */
}
} else {
login_resp->isp_data = 0;
login_resp->isp_datalen = 0;
}
return (login_resp);
}
static kv_status_t
{
/*
* Any key not understood by the acceptor may be igonred
* by the acceptor without affecting the basic function.
* However, the answer for a key not understood MUST be
* key=NotUnderstood.
*/
} else {
if (kvrc == KV_UNHANDLED) {
switch (lsm->icl_login_csg) {
break;
break;
case ISCSI_FULL_FEATURE_PHASE:
default:
/* What are we doing here? */
ASSERT(0);
kvrc = KV_UNHANDLED;
}
}
}
return (kvrc);
}
static kv_status_t
const idm_kv_xlate_t *ikvx)
{
char *string_val;
int nvrc;
case KI_INITIATOR_NAME:
case KI_INITIATOR_ALIAS:
break;
case KI_TARGET_NAME:
/* We'll validate the target during login_sm_session_bind() */
break;
case KI_TARGET_ALIAS:
case KI_TARGET_ADDRESS:
break;
case KI_SESSION_TYPE:
/*
* If we don't receive this key on the initial login
* we assume this is a normal session.
*/
break;
default:
/*
* This is not really an error but we should
* leave this nvpair on the list since we
* didn't do anything with it. Either
* the security or operational phase
* handling functions should process it.
*/
kvrc = KV_UNHANDLED;
break;
}
return (kvrc);
}
static kv_status_t
const idm_kv_xlate_t *ikvx)
{
/*
* After all of security keys are handled, this function will
* be called again to verify current authentication status
* and perform some actual authentication work. At this time,
* the nvp and ikvx will be passed in as NULLs.
*/
} else {
kv_id = 0;
}
if (handler) {
} else {
}
return (kvrc);
}
static kv_status_t
{
}
static kv_status_t
const idm_kv_xlate_t *ikvx)
{
int nvrc;
/*
* Retrieve values. All value lookups are expected to succeed
* since we build the nvlist while decoding the text buffer. This
* step is intended to eliminate some duplication of code (for example
* we only need to code the numerical value lookup once). We will
* handle the values (if necessary) below.
*/
/* Lists */
case KI_HEADER_DIGEST:
case KI_DATA_DIGEST:
break;
/* Booleans */
case KI_INITIAL_R2T:
case KI_IMMEDIATE_DATA:
case KI_DATA_PDU_IN_ORDER:
case KI_IFMARKER:
case KI_OFMARKER:
break;
/* Numericals */
case KI_MAX_CONNECTIONS:
case KI_MAX_BURST_LENGTH:
case KI_FIRST_BURST_LENGTH:
case KI_DEFAULT_TIME_2_WAIT:
case KI_DEFAULT_TIME_2_RETAIN:
case KI_MAX_OUTSTANDING_R2T:
case KI_ERROR_RECOVERY_LEVEL:
break;
/* Ranges */
case KI_OFMARKERINT:
case KI_IFMARKERINT:
break;
default:
break;
}
/*
* Now handle the values according to the key name. Sometimes we
* don't care what the value is -- in that case we just add the nvpair
* to the negotiated values list.
*/
case KI_HEADER_DIGEST:
break;
case KI_DATA_DIGEST:
break;
case KI_INITIAL_R2T:
/* We *require* INITIAL_R2T=yes */
B_TRUE);
break;
case KI_IMMEDIATE_DATA:
bool_val);
break;
case KI_DATA_PDU_IN_ORDER:
B_TRUE);
break;
/* We allow any value for DATA_SEQUENCE_IN_ORDER */
bool_val);
break;
case KI_OFMARKER:
case KI_IFMARKER:
/* We don't support markers */
B_FALSE);
break;
case KI_MAX_CONNECTIONS:
break;
/* this is a declartive param */
break;
case KI_MAX_BURST_LENGTH:
break;
case KI_FIRST_BURST_LENGTH:
break;
case KI_DEFAULT_TIME_2_WAIT:
break;
case KI_DEFAULT_TIME_2_RETAIN:
break;
case KI_MAX_OUTSTANDING_R2T:
break;
case KI_ERROR_RECOVERY_LEVEL:
break;
case KI_OFMARKERINT:
case KI_IFMARKERINT:
break;
default:
break;
}
return (kvrc);
}
static kv_status_t
{
int nvrc;
return (kvrc);
}
static kv_status_t
{
int nvrc;
return (kvrc);
}
static kv_status_t
const idm_kv_xlate_t *ikvx)
{
int nvrc;
char *digest_choice_string;
/*
* Need to add persistent config here if we want users to allow
* disabling of digests on the target side. You could argue that
* this makes things too complicated... just let the initiator state
* what it wants and we'll take it. For now that's exactly what
* we'll do.
*
* Basic digest negotiation happens here at iSCSI level. IDM
* can override this during negotiate_key_values phase to
* decline to set up any digest processing.
*/
/*
* Loop through all choices. As soon as we find a choice
* that we support add the value to our negotiated values list
* and respond with that value in the login response.
*/
while (digest_choice != NULL) {
/* Add to negotiated values list */
if (nvrc == 0) {
/* Add to login response list */
}
break;
}
}
if (digest_choice == NULL)
return (kvrc);
}
static kv_status_t
{
int nvrc;
if (ikvx->ik_declarative) {
} else {
if (value != iscsit_value) {
/* Respond back to initiator with our value */
} else {
/* Add this to our negotiated values */
nvp);
}
/* Response of Simple-value Negotiation */
if (nvrc == 0) {
}
}
return (kvrc);
}
static kv_status_t
const idm_kv_xlate_t *ikvx,
{
int nvrc;
/* Validate against standard */
} else if (ikvx->ik_declarative) {
} else {
if (value > iscsit_max_value) {
/* Respond back to initiator with our value */
} else {
/* Add this to our negotiated values */
nvp);
}
/* Response of Simple-value Negotiation */
if (nvrc == 0) {
}
}
return (kvrc);
}
static void
{
char *string_val;
int nvrc;
/* Let the IDM level activate its parameters first */
/*
* Initiator alias and target alias
*/
}
}
/*
* Operational parameters. We process SessionType when it is
* initially received since it is required on the initial login.
*/
}
}
}
}
}
}
}
}
}
}
}
}
}
static idm_status_t
{
int nvrc;
goto alloc_fail;
}
max_dataseglen_target)) != 0) {
goto done;
}
done:
if (error_class == ISCSI_STATUS_CLASS_SUCCESS) {
} else {
}
return (idm_status);
}
static char *
{
char *ret;
const char *sns;
int errnum;
return (NULL);
/* Check for one of the supported name types */
} else {
return (NULL);
}
/* Fold the case and normalize string */
return (NULL);
}
/* Copy the name type prefix */
return (ret);
}