iscsi_login.c revision 1a1a84a324206b6b1f5f704ab166c4ebf78aed76
/*
* 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 2000 by Cisco Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* iSCSI protocol login and enumeration
*/
#include "iscsi.h"
#include <sys/iscsi_protocol.h>
/* internal login protocol interfaces */
char **value_start, char **value_end);
int auth_status);
char *address);
/*
* +--------------------------------------------------------------------+
* | External Login Interface |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_login_start - connect and perform iscsi protocol login
*/
iscsi_login_start(void *arg)
{
char *buf;
unsigned char status_class;
unsigned char status_detail;
int login_buf_size;
/* reset connection statsn */
icp->conn_expstatsn = 0;
icp->conn_laststatsn = 0;
/* sync up authentication information */
(void) iscsi_sess_set_auth(isp);
/* sync up login and session parameters */
/* unable to sync params. fail connection attempts */
return (ISCSI_STATUS_LOGIN_FAILED);
}
/* delay the login process if required */
lbolt = ddi_get_lbolt();
}
/* Attempt to open TCP connection */
/* retry this failure */
goto login_retry;
}
/*
* allocate response buffer with based on default max
* transfer size. This size might shift during login.
*/
/* Start protocol login */
/* done with buffer */
/* hard failure in login */
if (!ISCSI_SUCCESS(rval)) {
/*
* We should just give up retry if these failures are
* detected.
*/
switch (rval) {
/*
* We should just give up retry if these
* failures are detected.
*/
case ISCSI_STATUS_NEGO_FAIL:
/* we don't want to retry this failure */
return (ISCSI_STATUS_LOGIN_FAILED);
default:
/* retry this failure */
goto login_retry;
}
}
/* soft failure with reason */
switch (status_class) {
/* login was successful */
return (ISCSI_STATUS_SUCCESS);
/* Retry at the redirected address */
goto login_start;
/* retry this failure */
goto login_retry;
default:
/* All other errors are hard failures */
"%s (0x%02x/0x%02x) Target: %s, TPGT: %d",
/* we don't want to retry this failure */
break;
}
return (ISCSI_STATUS_LOGIN_FAILED);
/* retry this failure if we haven't run out of time */
} else {
}
goto login_start;
} else {
DDI_SUCCESS) {
}
return (ISCSI_STATUS_SUCCESS);
}
} else {
/* Retries exceeded */
}
return (ISCSI_STATUS_LOGIN_FAILED);
}
static void
{
/* If login failed reset nego tpgt */
if (event != ISCSI_CONN_EVENT_T5) {
}
}
}
/*
* +--------------------------------------------------------------------+
* | Begin of protocol login routines |
* +--------------------------------------------------------------------+
*/
/*
* iscsi_login - Attempt to login to the target. The caller
* must check the status class to determine if the login succeeded.
* A return of 1 does not mean the login succeeded, it just means
* this function worked, and the status class is valid info. This
* allows the caller to decide whether or not to retry logins, so
* that we don't have any policy logic here.
*/
static iscsi_status_t
{
int max_data_length = 0;
/*
* prepare the connection
*/
icp->conn_partial_response = 0;
/*
* prepare for authentication
*/
"unable to initialize authentication",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
goto iscsi_login_done;
}
goto iscsi_login_done;
}
goto iscsi_login_done;
}
goto iscsi_login_done;
}
"unable to set remote authentication",
goto iscsi_login_done;
}
}
/*
* exchange PDUs until the login stage is complete, or an error occurs
*/
do {
/* setup */
/*
* fill in the PDU header and text data based on the
* login stage that we're in
*/
if (!ISCSI_SUCCESS(rval)) {
goto iscsi_login_done;
}
/* send a PDU to the target */
if (!ISCSI_SUCCESS(rval)) {
goto iscsi_login_done;
}
/* read the target's response into the same buffer */
sizeof (ihp), ISCSI_RX_TIMEOUT_VALUE, 0);
if (!ISCSI_SUCCESS(rval)) {
if (rval == ISCSI_STATUS_RX_TIMEOUT) {
#define STRING_FTRLRT "failed to receive login response - timeout"
"iscsi connection(%u) login failed - "
} else {
"iscsi connection(%u) login failed - "
"failed to receive login response",
}
goto iscsi_login_done;
}
if (!ISCSI_SUCCESS(rval)) {
"failed to receive login response",
goto iscsi_login_done;
}
/* check the PDU response type */
"received invalid login response (0x%02x)",
goto iscsi_login_done;
}
/*
* give the caller the status class and detail from the
* last login response PDU received
*/
if (status_class) {
}
if (status_detail) {
}
switch (ilrhp->status_class) {
/*
* process this response and possibly continue
* sending PDUs
*/
/* pass back whatever error we discovered */
if (!ISCSI_SUCCESS(rval)) {
goto iscsi_login_done;
}
break;
/*
* we need to process this response to get the
* TargetAddress of the redirect, but we don't
* care about the return code.
*/
goto iscsi_login_done;
if (ilrhp->status_detail ==
"failed - login failed to authenticate "
}
goto iscsi_login_done;
default:
/*
* some sort of error, login terminated unsuccessfully,
* though this function did it's job. the caller must
* check the status_class and status_detail and decide
* what to do next.
*/
goto iscsi_login_done;
}
if (auth_client) {
if (iscsiAuthClientFinish(auth_client) !=
"failed - login failed to authenticate "
if (ISCSI_SUCCESS(rval))
}
}
return (rval);
}
/*
* iscsi_make_login_pdu -
*
*/
static iscsi_status_t
char *data, int max_data_length)
{
int transit = 0;
int keytype = 0;
int rc = 0;
char value[iscsiAuthStringMaxLength];
/*
* initialize the PDU header
*/
/* don't increment on immediate */
/*
* we have to send 0 until full-feature stage
*/
/*
* the very first Login PDU has some additional requirements,
* * and we need to decide what stage to start in.
*/
"InitiatorName",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
} else {
"failed - initiator name is required",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
"InitiatorAlias",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
"SessionType", "Normal")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
"SessionType", "Discovery")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
} else {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
if (auth_client) {
/* we're prepared to do authentication */
} else {
/* can't do any authentication, skip that stage */
}
}
/*
* fill in text based on the stage
*/
switch (icp->conn_current_stage) {
/*
* we always try to go from op params to full
* feature stage
*/
transit = 1;
/*
* The terminology here may have gotten dated. A partial
* response is a login response that doesn't complete a
* login. If we haven't gotten a partial response, then
* either we shouldn't be here, or we just switched to
* this stage, and need to start offering keys.
*/
if (!icp->conn_partial_response) {
/*
* request the desired settings the first time
* we are in this stage
*/
case ISCSI_DIGEST_NONE:
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
case ISCSI_DIGEST_CRC32C:
"HeaderDigest", "CRC32C")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
case ISCSI_DIGEST_CRC32C_NONE:
max_data_length, "HeaderDigest",
"CRC32C,None")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
default:
case ISCSI_DIGEST_NONE_CRC32C:
max_data_length, "HeaderDigest",
"None,CRC32C")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
}
case ISCSI_DIGEST_NONE:
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
case ISCSI_DIGEST_CRC32C:
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
case ISCSI_DIGEST_CRC32C_NONE:
max_data_length, "DataDigest",
"CRC32C,None")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
default:
case ISCSI_DIGEST_NONE_CRC32C:
max_data_length, "DataDigest",
"None,CRC32C")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
break;
}
"MaxRecvDataSegmentLength", value)) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
max_data_length, "IFMarker",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
max_data_length, "OFMarker",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/*
* The following login parameters are "Irrelevant"
* for discovery sessions
*/
max_data_length, "InitialR2T",
"Yes" : "No")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
max_data_length, "ImmediateData",
"Yes" : "No")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
return (ISCSI_STATUS_INTERNAL_ERROR);
}
"FirstBurstLength", value)) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
"MaxOutstandingR2T", value)) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
"MaxConnections", value)) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
max_data_length, "DataPDUInOrder",
"Yes" : "No")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
max_data_length, "DataSequenceInOrder",
"Yes" : "No")) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
}
break;
/*
* see if we're ready for a stage change
*/
if (rc == iscsiAuthStatusNoError) {
if (transit) {
} else {
}
} else {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/*
* enumerate all the keys the auth code might want to send
*/
while (iscsiAuthClientGetNextKeyType(&keytype) ==
int present = 0;
unsigned int max_length = max_data_length -
/*
* send directly to the PDU, since they could in
* theory be large.
*/
/*
* actually fill in the key
*/
pdu_length += key_length;
pdu_length++;
/*
* adjust the PDU's data segment length to
* include the value and trailing NULL
*/
}
}
break;
case ISCSI_FULL_FEATURE_PHASE:
"failed - can't send login in full feature stage",
return (ISCSI_STATUS_INTERNAL_ERROR);
default:
"failed - can't send login in unknown stage (%d)",
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/* fill in the flags */
if (transit) {
/* transit to the next stage */
} else {
/* next == current */
}
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_process_login_response - This assumes the text data is
* always NUL terminated. The caller can always arrange for that by
* using a slightly larger buffer than the max PDU size, and then
* appending a NUL to the PDU.
*/
static iscsi_status_t
{
int transit = 0;
int pdu_current_stage = 0;
int pdu_next_stage = 0;
int debug_status = 0;
unsigned long tmp;
char *tmpe;
/* verify the initial buffer was big enough to hold everything */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
*end = '\0';
/* if the response status was success, sanity check the response */
/* check the active version */
"failed - target version incompatible "
"received:0x%0x2x expected:0x%02x",
return (ISCSI_STATUS_VERSION_MISMATCH);
}
/* make sure the current stage matches */
"failed - login response contained invalid "
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
/*
* Make sure that we're actually advancing
* if the T-bit is set
*/
"failed - login response wants to go to stage "
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
}
if (iscsiAuthClientRecvBegin(auth_client) !=
return (ISCSI_STATUS_INTERNAL_ERROR);
}
transit) != iscsiAuthStatusNoError) {
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
/*
* scan the text data
*/
/*
* skip any NULs separating each text key=value pair
*/
text++;
}
break;
}
/*
* handle keys appropriate for each stage
*/
switch (icp->conn_current_stage) {
/*
* a few keys are possible in Security stage
* * which the auth code doesn't care about,
* * but which we might want to see, or at
* * least not choke on.
*/
if (iscsi_find_key_value("TargetAlias",
isp->sess_alias_length) {
}
'\0';
} else if (iscsi_find_key_value("TargetAddress",
"login failed - login redirection "
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value("TargetPortalGroupTag",
/*
* We should have already obtained this via
* discovery. We've already picked an isid,
* so the most we can do is confirm we reached
* the portal group we were expecting to.
*/
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
"protocol group tag mismatch, expected %d, received %lu",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
}
} else {
/*
* any key we don't recognize either goes
* to the auth code, or we choke on it
*/
int keytype = iscsiAuthKeyTypeNone;
while (iscsiAuthClientGetNextKeyType(
&keytype) == iscsiAuthStatusNoError) {
char *key =
(char *)iscsiAuthClientGetKeyName(
keytype);
if ((key) &&
value) !=
return (ISCSI_STATUS_NEGO_FAIL);
}
goto more_text;
}
}
return (ISCSI_STATUS_NEGO_FAIL);
}
break;
isp->sess_alias_length) {
}
'\0';
} else if (iscsi_find_key_value("TargetAddress",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value("TargetPortalGroupTag",
/*
* We should have already obtained this via
* discovery. We've already picked an isid,
* so the most we can do is confirm we reached
* the portal group we were expecting to.
*/
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
}
} else if (iscsi_find_key_value("InitialR2T",
/*
* iSCSI RFC section 12.10 states that
* InitialR2T is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value("ImmediateData",
/*
* iSCSI RFC section 12.11 states that
* ImmediateData is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - ImmediateData is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
"login failed - ImmediateData is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value(
"login failed - MaxRecvDataSegment"
"Length is invalid - protocol "
return (ISCSI_STATUS_NEGO_FAIL);
}
(int)tmp;
} else if (iscsi_find_key_value("FirstBurstLength",
/*
* iSCSI RFC section 12.14 states that
* FirstBurstLength is Irrelevant if
* InitialR2T=Yes and ImmediateData=No
* or is this is a discovery session.
*/
/* EMPTY */
} else if (value &&
/* irrelevant */
} else if (ddi_strtoul(
/* bad value */
"login failed - FirstBurstLength"
"is invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
/* good value */
(int)tmp;
}
} else if (iscsi_find_key_value("MaxBurstLength",
/*
* iSCSI RFC section 12.13 states that
* MaxBurstLength is Irrelevant for a
* discovery session.
*/
/* EMPTY */
} else if (ddi_strtoul(
"login failed - MaxBurstLength"
"is invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
(int)tmp;
}
} else if (iscsi_find_key_value("HeaderDigest",
} else {
"connection(%u) login "
"failed - HeaderDigest="
"CRC32 is required, can't "
"accept %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"connection(%u) login "
"failed - HeaderDigest="
"None is required, can't "
"accept %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"login failed - HeaderDigest "
text);
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"connection(%u) login "
"failed - DataDigest="
"CRC32C is required, "
"can't accept %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"connection(%u) login "
"failed - DataDigest=None "
"is required, can't "
"accept %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"login failed - can't accept %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else if (iscsi_find_key_value("DefaultTime2Wait",
"login failed - DefaultTime2Wait "
"is invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
(int)tmp;
} else if (iscsi_find_key_value("DefaultTime2Retain",
"login failed - DefaultTime2Retain "
"is invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
(int)tmp;
/*
* result function is AND, target must
* honor our No
*/
/*
* we don't do markers, so we don't care
*/
/*
* result function is AND, target must
* honor our No
*/
/*
* we don't do markers, so we don't care
*/
} else if (iscsi_find_key_value("DataPDUInOrder",
/*
* iSCSI RFC section 12.18 states that
* DataPDUInOrder is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value("DataSequenceInOrder",
/*
* iSCSI RFC section 12.19 states that
* DataSequenceInOrder is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
} else {
"login failed - InitialR2T is "
"invalid - protocol error",
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
} else if (iscsi_find_key_value("MaxOutstandingR2T",
/*
* iSCSI RFC section 12.17 states that
* MaxOutstandingR2T is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - can't accept "
"MaxOutstandingR2T %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else if (iscsi_find_key_value("MaxConnections",
/*
* iSCSI RFC section 12.2 states that
* MaxConnections is Irrelevant for a
* discovery session.
*/
/* EMPTY */
"login failed - can't accept "
"MaxConnections %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else if (iscsi_find_key_value("ErrorRecoveryLevel",
"login failed - can't accept "
"ErrorRecoveryLevel %s",
return (ISCSI_STATUS_NEGO_FAIL);
}
} else {
"login failed - ignoring login "
}
break;
default:
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
/*
* iSCSI RFC section 12.14 states that
* FirstBurstLength is Irrelevant if
* InitialR2T=Yes and ImmediateData=No.
* This is a final check to make sure
* the array didn't make a protocol
* violation.
*/
if ((fbl_irrelevant == B_TRUE) &&
"FirstBurstLength=Irrelevant and (InitialR2T!=Yes or "
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
case iscsiAuthStatusContinue:
/*
* continue sending PDUs
*/
break;
case iscsiAuthStatusPass:
break;
/*
* this should only occur if we were authenticating the
* target, which we don't do yet, so treat this as an
* error.
*/
case iscsiAuthStatusNoError:
/*
* treat this as an error, since we should get a
* different code
*/
case iscsiAuthStatusError:
case iscsiAuthStatusFail:
default:
debug_status = 0;
&debug_status) != iscsiAuthStatusNoError) {
"failed - authentication failed with "
debug_status));
} else {
"failed - authentication failed with "
}
return (ISCSI_STATUS_AUTHENTICATION_FAILED);
}
}
/*
* record some of the PDU fields for later use
*/
}
if (transit) {
/*
* advance to the next stage
*/
icp->conn_partial_response = 0;
} else {
/*
* we got a partial response, don't advance, more
* negotiation to do
*/
}
/*
* this PDU is ok, though the login process
* may not be done yet
*/
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_add_text - caller is assumed to be well-behaved and passing NUL
* terminated strings
*/
int
{
int param_len = 0;
int value_len = 0;
int length = 0;
int pdu_length = 0;
/* param, separator, value, and trailing NULL */
pdu_length += length;
return (0);
}
/* param */
/* separator */
*text++ = ISCSI_TEXT_SEPARATOR;
/* value */
/* NULL */
*text++ = '\0';
/* update the length in the PDU header */
return (1);
}
/*
* iscsi_get_next_text - get the next line of text from the given data
* buffer. This function searches from the address given for the
* curr_text parameter. If curr_text_parameter is NULL return first
* line in buffer. The return value is the address of the next line
* based upon where curr_text is located.
*
*/
char *
{
char *curr_data;
/* check if any data exists, if not return */
if (max_data_length == 0) {
return (NULL);
}
/* handle first call to this function */
return (data);
}
/* move to next text string */
curr_data++;
}
curr_data++; /* go past the NULL to the next entry */
/* check whether data end reached */
return (NULL);
}
return (curr_data);
}
/*
* iscsi_find_key_value -
*
*/
static int
char **value_start, char **value_end)
{
if (value_start)
*value_start = NULL;
if (value_end)
/*
* make sure they contain the same bytes
*/
while (*str) {
return (0);
}
if (*text == '\0') {
return (0);
}
return (0);
}
str++;
text++;
}
(*text == '\0') ||
(*text != ISCSI_TEXT_SEPARATOR)) {
return (0);
}
/*
* find the value
*/
/*
* find the end of the value
*/
text++;
if (value_start)
*value_start = value;
if (value_end)
return (1);
}
/*
* iscsi_update_address - This function is used on a login redirection.
* During the login redirection we are asked to switch to an IP address
* port different than the one we were logging into.
*/
static iscsi_status_t
{
int type;
unsigned long tmp;
int error_num;
int port;
/* parse login redirection response */
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
/* convert addr_str */
if (!hptr) {
return (ISCSI_STATUS_PROTOCOL_ERROR);
}
/* convert port_str */
} else {
}
return (ISCSI_STATUS_SUCCESS);
}
/*
* iscsi_null_callback - This callback may be used under certain
* conditions when authenticating a target, but I'm not sure what
* we need to do here.
*/
/* ARGSUSED */
static void
{
}
/*
* iscsi_login_failure_str -
*
*/
static char *
{
switch (status_class) {
case 0x00:
switch (status_detail) {
case 0x00:
return ("Login is proceeding okay.");
default:
break;
}
case 0x01:
switch (status_detail) {
case 0x01:
return ("Requested ITN has moved temporarily to "
"the address provided.");
case 0x02:
return ("Requested ITN has moved permanently to "
"the address provided.");
default:
break;
}
case 0x02:
switch (status_detail) {
case 0x00:
return ("Miscellaneous iSCSI initiator errors.");
case 0x01:
return ("Initiator could not be successfully "
"authenticated.");
case 0x02:
return ("Initiator is not allowed access to the "
"given target.");
case 0x03:
return ("Requested ITN does not exist at this "
"address.");
case 0x04:
return ("Requested ITN has been removed and no "
"forwarding address is provided.");
case 0x05:
return ("Requested iSCSI version range is not "
"supported by the target.");
case 0x06:
return ("No more connections can be accepted on "
"this Session ID (SSID).");
case 0x07:
return ("Missing parameters (e.g., iSCSI initiator "
case 0x08:
return ("Target does not support session spanning "
"to this connection (address).");
case 0x09:
return ("Target does not support this type of "
"session or not from this initiator.");
case 0x0A:
return ("Attempt to add a connection to a "
"nonexistent session.");
case 0x0B:
return ("Invalid request type during login.");
default:
break;
}
case 0x03:
switch (status_detail) {
case 0x00:
return ("Target hardware or software error.");
case 0x01:
return ("iSCSI service or target is not currently "
"operational.");
case 0x02:
return ("Target has insufficient session, connection "
"or other resources.");
default:
break;
}
}
return ("Unknown login response received.");
}
/*
* iscsi_login_connect -
*/
static iscsi_status_t
{
struct sockaddr_in6 t_addr;
t_addrlen = sizeof (struct sockaddr_in6);
return (ISCSI_STATUS_INTERNAL_ERROR);
}
/* bind if enabled */
/* bind socket */
SIZEOF_SOCKADDR(addr), 0, 0)) {
}
}
/* Make sure that scope_id is zero if it is an IPv6 address */
}
/* connect socket to target portal (ip,port) */
SIZEOF_SOCKADDR(addr), 0, 0))) {
/* ---- 2 indicates both cantsend and cantrecv ---- */
return (ISCSI_STATUS_INTERNAL_ERROR);
}
}
return (ISCSI_STATUS_SUCCESS);
}