Login: remember what the TargetAddress returned during login is so we can
handle redirect 'errors'.
This commit is contained in:
@@ -55,6 +55,7 @@ enum iscsi_immediate_data {
|
|||||||
struct iscsi_context {
|
struct iscsi_context {
|
||||||
const char *initiator_name;
|
const char *initiator_name;
|
||||||
const char *target_name;
|
const char *target_name;
|
||||||
|
const char *target_address; /* If a redirect */
|
||||||
const char *alias;
|
const char *alias;
|
||||||
|
|
||||||
const char *user;
|
const char *user;
|
||||||
|
|||||||
@@ -151,6 +151,11 @@ int iscsi_set_alias(struct iscsi_context *iscsi, const char *alias);
|
|||||||
*/
|
*/
|
||||||
int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname);
|
int iscsi_set_targetname(struct iscsi_context *iscsi, const char *targetname);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function returns any target address supplied in a login response when
|
||||||
|
* the target has moved.
|
||||||
|
*/
|
||||||
|
const char *iscsi_get_target_address(struct iscsi_context *iscsi);
|
||||||
|
|
||||||
/* Type of iscsi sessions. Discovery sessions are used to query for what
|
/* Type of iscsi sessions. Discovery sessions are used to query for what
|
||||||
* targets exist behind the portal connected to. Normal sessions are used to
|
* targets exist behind the portal connected to. Normal sessions are used to
|
||||||
|
|||||||
+10
@@ -202,6 +202,9 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
|
|||||||
free(discard_const(iscsi->target_name));
|
free(discard_const(iscsi->target_name));
|
||||||
iscsi->target_name = NULL;
|
iscsi->target_name = NULL;
|
||||||
|
|
||||||
|
free(discard_const(iscsi->target_address));
|
||||||
|
iscsi->target_address = NULL;
|
||||||
|
|
||||||
free(discard_const(iscsi->alias));
|
free(discard_const(iscsi->alias));
|
||||||
iscsi->alias = NULL;
|
iscsi->alias = NULL;
|
||||||
|
|
||||||
@@ -257,6 +260,13 @@ iscsi_get_error(struct iscsi_context *iscsi)
|
|||||||
return iscsi->error_string;
|
return iscsi->error_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
iscsi_get_target_address(struct iscsi_context *iscsi)
|
||||||
|
{
|
||||||
|
return iscsi->target_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iscsi_set_header_digest(struct iscsi_context *iscsi,
|
iscsi_set_header_digest(struct iscsi_context *iscsi,
|
||||||
enum iscsi_header_digest header_digest)
|
enum iscsi_header_digest header_digest)
|
||||||
|
|||||||
+43
-29
@@ -886,6 +886,7 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
|
|||||||
static const char *login_error_str(int status)
|
static const char *login_error_str(int status)
|
||||||
{
|
{
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
case 0x0100: return "Target moved (unknown)"; /* Some don't set the detail */
|
||||||
case 0x0101: return "Target moved temporarily";
|
case 0x0101: return "Target moved temporarily";
|
||||||
case 0x0102: return "Target moved permanently";
|
case 0x0102: return "Target moved permanently";
|
||||||
case 0x0200: return "Initiator error";
|
case 0x0200: return "Initiator error";
|
||||||
@@ -913,17 +914,10 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
struct iscsi_in_pdu *in)
|
struct iscsi_in_pdu *in)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
unsigned char *ptr = in->data;
|
char *ptr = (char *)in->data;
|
||||||
int size = in->data_pos;
|
int size = in->data_pos;
|
||||||
|
|
||||||
status = ntohs(*(uint16_t *)&in->hdr[36]);
|
status = ntohs(*(uint16_t *)&in->hdr[36]);
|
||||||
if (status != 0) {
|
|
||||||
iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)",
|
|
||||||
login_error_str(status), status);
|
|
||||||
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
|
||||||
pdu->private_data);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
iscsi->statsn = ntohs(*(uint16_t *)&in->hdr[24]);
|
iscsi->statsn = ntohs(*(uint16_t *)&in->hdr[24]);
|
||||||
|
|
||||||
@@ -936,7 +930,7 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = strlen((char *)ptr);
|
len = strlen(ptr);
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
break;
|
break;
|
||||||
@@ -951,8 +945,20 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* parse the strings */
|
/* parse the strings */
|
||||||
if (!strncmp((char *)ptr, "HeaderDigest=", 13)) {
|
if (!strncmp(ptr, "TargetAddress=", 14)) {
|
||||||
if (!strcmp((char *)ptr + 13, "CRC32C")) {
|
free(discard_const(iscsi->target_address));
|
||||||
|
iscsi->target_address = strdup(ptr+14);
|
||||||
|
if (iscsi->target_address == NULL) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to allocate"
|
||||||
|
" target address");
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncmp(ptr, "HeaderDigest=", 13)) {
|
||||||
|
if (!strcmp(ptr + 13, "CRC32C")) {
|
||||||
iscsi->header_digest
|
iscsi->header_digest
|
||||||
= ISCSI_HEADER_DIGEST_CRC32C;
|
= ISCSI_HEADER_DIGEST_CRC32C;
|
||||||
iscsi->want_header_digest
|
iscsi->want_header_digest
|
||||||
@@ -965,53 +971,53 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "FirstBurstLength=", 17)) {
|
if (!strncmp(ptr, "FirstBurstLength=", 17)) {
|
||||||
iscsi->first_burst_length = strtol((char *)ptr + 17, NULL, 10);
|
iscsi->first_burst_length = strtol(ptr + 17, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "InitialR2T=", 11)) {
|
if (!strncmp(ptr, "InitialR2T=", 11)) {
|
||||||
if (!strcmp((char *)ptr + 11, "No")) {
|
if (!strcmp(ptr + 11, "No")) {
|
||||||
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO;
|
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_NO;
|
||||||
} else {
|
} else {
|
||||||
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_YES;
|
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "ImmediateData=", 14)) {
|
if (!strncmp(ptr, "ImmediateData=", 14)) {
|
||||||
if (!strcmp((char *)ptr + 14, "No")) {
|
if (!strcmp(ptr + 14, "No")) {
|
||||||
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
|
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
|
||||||
} else {
|
} else {
|
||||||
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
|
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "MaxBurstLength=", 15)) {
|
if (!strncmp(ptr, "MaxBurstLength=", 15)) {
|
||||||
iscsi->max_burst_length = strtol((char *)ptr + 15, NULL, 10);
|
iscsi->max_burst_length = strtol(ptr + 15, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "MaxRecvDataSegmentLength=", 25)) {
|
if (!strncmp(ptr, "MaxRecvDataSegmentLength=", 25)) {
|
||||||
iscsi->target_max_recv_data_segment_length = strtol((char *)ptr + 25, NULL, 10);
|
iscsi->target_max_recv_data_segment_length = strtol(ptr + 25, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "AuthMethod=", 11)) {
|
if (!strncmp(ptr, "AuthMethod=", 11)) {
|
||||||
if (!strcmp((char *)ptr + 11, "CHAP")) {
|
if (!strcmp(ptr + 11, "CHAP")) {
|
||||||
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM;
|
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SELECT_ALGORITHM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "CHAP_A=", 7)) {
|
if (!strncmp(ptr, "CHAP_A=", 7)) {
|
||||||
iscsi->chap_a = atoi((char *)ptr+7);
|
iscsi->chap_a = atoi(ptr+7);
|
||||||
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "CHAP_I=", 7)) {
|
if (!strncmp(ptr, "CHAP_I=", 7)) {
|
||||||
iscsi->chap_i = atoi((char *)ptr+7);
|
iscsi->chap_i = atoi(ptr+7);
|
||||||
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_SEND_RESPONSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp((char *)ptr, "CHAP_C=0x", 9)) {
|
if (!strncmp(ptr, "CHAP_C=0x", 9)) {
|
||||||
free(iscsi->chap_c);
|
free(iscsi->chap_c);
|
||||||
iscsi->chap_c = strdup((char *)ptr+9);
|
iscsi->chap_c = strdup(ptr+9);
|
||||||
if (iscsi->chap_c == NULL) {
|
if (iscsi->chap_c == NULL) {
|
||||||
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup CHAP challenge.");
|
iscsi_set_error(iscsi, "Out-of-memory: Failed to strdup CHAP challenge.");
|
||||||
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data);
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL, pdu->private_data);
|
||||||
@@ -1024,6 +1030,14 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
|
|||||||
size -= len + 1;
|
size -= len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status != 0) {
|
||||||
|
iscsi_set_error(iscsi, "Failed to log in to target. Status: %s(%d)",
|
||||||
|
login_error_str(status), status);
|
||||||
|
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
|
||||||
|
pdu->private_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) {
|
if (in->hdr[1] & ISCSI_PDU_LOGIN_TRANSIT) {
|
||||||
iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2;
|
iscsi->current_phase = (in->hdr[1] & ISCSI_PDU_LOGIN_NSG_FF) << 2;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user