Files
libiscsi/lib/init.c
Peter Lieven 8c4e2ad46b feat: read and validate unit serial number after login
this patch adds a read of VPD page 0x80 (unit serial number) after successful login.

The serial is then validated on secutive reconnects to avoid the accidental mismatch
of LUN ids if some kind of remapping appears between loss of connection and a later
reconnect.

An additional url parameter force_usn is added to enforce the usn right from the beginning.
If not set via url or the new iscsi_set_unit_serial_number function the usn is learned
at the first successful login.

Signed-off-by: Peter Lieven <pl@dlhnet.de>
2025-09-11 15:15:42 +00:00

884 lines
20 KiB
C

/*
Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define _GNU_SOURCE
#if defined(_WIN32)
#include "win32/win32_compat.h"
#else
#include <strings.h>
#include <unistd.h>
#endif
#include <assert.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/types.h>
#include <time.h>
#include "iscsi.h"
#include "iscsi-private.h"
#ifdef HAVE_LINUX_ISER
#include "iser-private.h"
#endif
#include "slist.h"
/**
* Initialize transport type of session
*/
int iscsi_init_transport(struct iscsi_context *iscsi,
enum iscsi_transport_type transport) {
iscsi->transport = transport;
switch (iscsi->transport) {
case TCP_TRANSPORT:
iscsi_init_tcp_transport(iscsi);
break;
#ifdef HAVE_LINUX_ISER
case ISER_TRANSPORT:
iscsi_init_iser_transport(iscsi);
break;
#endif
default:
iscsi_set_error(iscsi, "Unfamiliar transport type");
return -1;
}
return 0;
}
/**
* Whether or not the internal memory allocator caches allocations. Disable
* memory allocation caching to improve the accuracy of Valgrind reports.
*/
void iscsi_set_cache_allocations(struct iscsi_context *iscsi, int ca)
{
iscsi->cache_allocations = ca;
}
void* iscsi_malloc(struct iscsi_context *iscsi, size_t size) {
void * ptr = malloc(size);
if (ptr != NULL) iscsi->mallocs++;
return ptr;
}
void* iscsi_zmalloc(struct iscsi_context *iscsi, size_t size) {
void * ptr = malloc(size);
if (ptr != NULL) {
memset(ptr,0x00,size);
iscsi->mallocs++;
}
return ptr;
}
void* iscsi_realloc(struct iscsi_context *iscsi, void* ptr, size_t size) {
void * _ptr = realloc(ptr, size);
if (_ptr != NULL) {
iscsi->reallocs++;
}
return _ptr;
}
void iscsi_free(struct iscsi_context *iscsi, void* ptr) {
if (ptr == NULL) return;
free(ptr);
iscsi->frees++;
}
char* iscsi_strdup(struct iscsi_context *iscsi, const char* str) {
char *str2 = strdup(str);
if (str2 != NULL) iscsi->mallocs++;
return str2;
}
static void
iscsi_srand_init(struct iscsi_context *iscsi) {
unsigned int seed;
int urand_fd;
ssize_t rc;
int err;
static bool rd_set = false;
static pthread_mutex_t rd_mutex = PTHREAD_MUTEX_INITIALIZER;
if (rd_set) {
/* fast case, seed has been set */
return;
}
err = pthread_mutex_lock(&rd_mutex);
assert(err == 0);
if (rd_set) {
/* another thread initialized it in the meantime */
goto out;
}
urand_fd = open("/dev/urandom", O_RDONLY);
if (urand_fd == -1) {
goto fallback;
}
rc = read(urand_fd, &seed, sizeof(seed));
close(urand_fd);
if (rc == -1) {
goto fallback;
}
srand(seed);
goto out;
fallback:
/* seed based on @iscsi */
srand(getpid() ^ (uint32_t)((uintptr_t) iscsi));
out:
rd_set = true;
err = pthread_mutex_unlock(&rd_mutex);
assert(err == 0);
}
struct iscsi_context *
iscsi_create_context(const char *initiator_name)
{
struct iscsi_context *iscsi;
char *ca;
if (!initiator_name[0]) {
return NULL;
}
iscsi = malloc(sizeof(struct iscsi_context));
if (iscsi == NULL) {
return NULL;
}
memset(iscsi, 0, sizeof(struct iscsi_context));
iscsi_mt_spin_init(&iscsi->iscsi_lock, PTHREAD_PROCESS_PRIVATE);
iscsi_mt_mutex_init(&iscsi->iscsi_mutex);
iscsi->poll_timeout = 100;
/* initalize transport of context */
if (iscsi_init_transport(iscsi, TCP_TRANSPORT)) {
free(iscsi);
return NULL;
}
strncpy(iscsi->initiator_name,initiator_name,MAX_ISCSI_NAME_SIZE);
iscsi->fd = -1;
/* initialize to a "random" isid */
iscsi_srand_init(iscsi);
iscsi_set_isid_random(iscsi, rand(), 0);
/* assume we start in security negotiation phase */
iscsi->current_phase = ISCSI_PDU_LOGIN_CSG_SECNEG;
iscsi->next_phase = ISCSI_PDU_LOGIN_NSG_OPNEG;
iscsi->secneg_phase = ISCSI_LOGIN_SECNEG_PHASE_OFFER_CHAP;
iscsi->max_burst_length = 262144;
iscsi->first_burst_length = 262144;
iscsi->initiator_max_recv_data_segment_length = 262144;
iscsi->target_max_recv_data_segment_length = 8192;
iscsi->want_initial_r2t = ISCSI_INITIAL_R2T_NO;
iscsi->use_initial_r2t = ISCSI_INITIAL_R2T_YES;
iscsi->want_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_YES;
iscsi->want_header_digest = ISCSI_HEADER_DIGEST_NONE_CRC32C;
iscsi->want_data_digest = ISCSI_DATA_DIGEST_NONE;
iscsi->tcp_keepcnt=3;
iscsi->tcp_keepintvl=30;
iscsi->tcp_keepidle=30;
iscsi->reconnect_max_retries = -1;
iscsi->chap_auth = ISCSI_CHAP_MD5;
if (getenv("LIBISCSI_DEBUG") != NULL) {
iscsi_set_log_level(iscsi, atoi(getenv("LIBISCSI_DEBUG")));
iscsi_set_log_fn(iscsi, iscsi_log_to_stderr);
}
if (getenv("LIBISCSI_TCP_USER_TIMEOUT") != NULL) {
iscsi_set_tcp_user_timeout(iscsi,atoi(getenv("LIBISCSI_TCP_USER_TIMEOUT")));
}
if (getenv("LIBISCSI_TCP_KEEPCNT") != NULL) {
iscsi_set_tcp_keepcnt(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPCNT")));
}
if (getenv("LIBISCSI_TCP_KEEPINTVL") != NULL) {
iscsi_set_tcp_keepintvl(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPINTVL")));
}
if (getenv("LIBISCSI_TCP_KEEPIDLE") != NULL) {
iscsi_set_tcp_keepidle(iscsi,atoi(getenv("LIBISCSI_TCP_KEEPIDLE")));
}
if (getenv("LIBISCSI_TCP_SYNCNT") != NULL) {
iscsi_set_tcp_syncnt(iscsi,atoi(getenv("LIBISCSI_TCP_SYNCNT")));
}
if (getenv("LIBISCSI_BIND_INTERFACES") != NULL) {
iscsi_set_bind_interfaces(iscsi,getenv("LIBISCSI_BIND_INTERFACES"));
}
if (getenv("LIBISCSI_RDMA_ACK_TIMEOUT") != NULL) {
iscsi->rdma_ack_timeout = atoi(getenv("LIBISCSI_RDMA_ACK_TIMEOUT"));
}
ca = getenv("LIBISCSI_CACHE_ALLOCATIONS");
if (!ca || atoi(ca) != 0) {
iscsi->cache_allocations = 1;
}
return iscsi;
}
int
iscsi_set_isid_oui(struct iscsi_context *iscsi, uint32_t oui, uint32_t qualifier)
{
iscsi->isid[0] = (oui >> 16) & 0x3f;
iscsi->isid[1] = (oui >> 8) & 0xff;
iscsi->isid[2] = (oui ) & 0xff;
iscsi->isid[3] = (qualifier >> 16) & 0xff;
iscsi->isid[4] = (qualifier >> 8) & 0xff;
iscsi->isid[5] = (qualifier ) & 0xff;
return 0;
}
int
iscsi_set_isid_en(struct iscsi_context *iscsi, uint32_t en, uint32_t qualifier)
{
iscsi->isid[0] = 0x40;
iscsi->isid[1] = (en >> 16) & 0xff;
iscsi->isid[2] = (en >> 8) & 0xff;
iscsi->isid[3] = (en ) & 0xff;
iscsi->isid[4] = (qualifier >> 8) & 0xff;
iscsi->isid[5] = (qualifier ) & 0xff;
return 0;
}
int
iscsi_set_isid_random(struct iscsi_context *iscsi, uint32_t rnd, uint32_t qualifier)
{
iscsi->isid[0] = 0x80;
iscsi->isid[1] = (rnd >> 16) & 0xff;
iscsi->isid[2] = (rnd >> 8) & 0xff;
iscsi->isid[3] = (rnd ) & 0xff;
iscsi->isid[4] = (qualifier >> 8) & 0xff;
iscsi->isid[5] = (qualifier ) & 0xff;
return 0;
}
int
iscsi_set_isid_reserved(struct iscsi_context *iscsi)
{
iscsi->isid[0] = 0xc0;
iscsi->isid[1] = 0x00;
iscsi->isid[2] = 0x00;
iscsi->isid[3] = 0x00;
iscsi->isid[4] = 0x00;
iscsi->isid[5] = 0x00;
return 0;
}
int
iscsi_set_alias(struct iscsi_context *iscsi, const char *alias)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when adding alias");
return -1;
}
strncpy(iscsi->alias,alias,MAX_STRING_SIZE);
return 0;
}
int
iscsi_set_targetname(struct iscsi_context *iscsi, const char *target_name)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when adding "
"targetname");
return -1;
}
strncpy(iscsi->target_name,target_name,MAX_ISCSI_NAME_SIZE);
return 0;
}
int
iscsi_set_unit_serial_number(struct iscsi_context *iscsi, const char *usn)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when adding "
"unit_serial_number");
return -1;
}
strncpy(iscsi->unit_serial_number,usn,MAX_STRING_SIZE);
return 0;
}
const char *
iscsi_get_unit_serial_number(struct iscsi_context *iscsi)
{
return iscsi ? iscsi->unit_serial_number : "";
}
int
iscsi_destroy_context(struct iscsi_context *iscsi)
{
if (iscsi == NULL) {
return 0;
}
iscsi_disconnect(iscsi);
iscsi_cancel_pdus(iscsi);
iscsi_mt_spin_lock(&iscsi->iscsi_lock);
if (iscsi->outqueue_current != NULL && iscsi->outqueue_current->flags & ISCSI_PDU_DELETE_WHEN_SENT) {
iscsi->drv->free_pdu(iscsi, iscsi->outqueue_current);
}
if (iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(iscsi, iscsi->incoming);
}
iscsi_mt_spin_unlock(&iscsi->iscsi_lock);
iscsi->connect_data = NULL;
iscsi_free(iscsi, iscsi->opaque);
if (iscsi->mallocs != iscsi->frees) {
ISCSI_LOG(iscsi,1,"%d memory blocks lost at iscsi_destroy_context() after %d malloc(s), %d realloc(s), %d free(s)",iscsi->mallocs-iscsi->frees,iscsi->mallocs,iscsi->reallocs,iscsi->frees);
} else {
ISCSI_LOG(iscsi,5,"memory is clean at iscsi_destroy_context() after %d mallocs, %d realloc(s), %d free(s)",iscsi->mallocs,iscsi->reallocs,iscsi->frees);
}
if (iscsi->old_iscsi) {
iscsi->old_iscsi->fd = -1;
iscsi_destroy_context(iscsi->old_iscsi);
}
iscsi_mt_spin_destroy(&iscsi->iscsi_lock);
iscsi_mt_mutex_destroy(&iscsi->iscsi_mutex);
memset(iscsi, 0, sizeof(struct iscsi_context));
free(iscsi);
return 0;
}
void
iscsi_set_error(struct iscsi_context *iscsi, const char *error_string, ...)
{
va_list ap;
char errstr[MAX_STRING_SIZE + 1] = {0};
va_start(ap, error_string);
if (vsnprintf(errstr, MAX_STRING_SIZE, error_string, ap) < 0) {
strncpy(errstr, "could not format error string!", MAX_STRING_SIZE);
}
va_end(ap);
if (iscsi != NULL) {
strncpy(iscsi->error_string, errstr,MAX_STRING_SIZE);
ISCSI_LOG(iscsi, 1, "%s",iscsi->error_string);
}
}
void
iscsi_set_log_level(struct iscsi_context *iscsi, int level)
{
iscsi->log_level = level;
ISCSI_LOG(iscsi, 2, "set log level to %d", level);
}
const char *
iscsi_get_error(struct iscsi_context *iscsi)
{
return iscsi ? iscsi->error_string : "";
}
const char *
iscsi_get_target_address(struct iscsi_context *iscsi)
{
return iscsi->target_address;
}
int
iscsi_set_header_digest(struct iscsi_context *iscsi,
enum iscsi_header_digest header_digest)
{
if (iscsi->is_loggedin) {
iscsi_set_error(iscsi, "trying to set header digest while "
"logged in");
return -1;
}
if ((unsigned)header_digest > ISCSI_HEADER_DIGEST_LAST) {
iscsi_set_error(iscsi, "invalid header digest value");
return -1;
}
iscsi->want_header_digest = header_digest;
return 0;
}
int
iscsi_set_data_digest(struct iscsi_context *iscsi,
enum iscsi_data_digest data_digest)
{
if (iscsi->is_loggedin) {
iscsi_set_error(iscsi, "trying to set data digest while "
"logged in");
return -1;
}
if ((unsigned)data_digest > ISCSI_DATA_DIGEST_LAST) {
iscsi_set_error(iscsi, "invalid data digest value");
return -1;
}
iscsi->want_data_digest = data_digest;
return 0;
}
int
iscsi_is_logged_in(struct iscsi_context *iscsi)
{
return iscsi->is_loggedin;
}
static int
h2i(int h)
{
if (h >= 'a' && h <= 'f') {
return h - 'a' + 10;
}
if (h >= 'A' && h <= 'F') {
return h - 'A' + 10;
}
return h - '0';
}
static void
iscsi_decode_url_string(char *str)
{
while (*str) {
char *tmp = str;
char c;
if (*str++ != '%') {
continue;
}
if (*str == 0) {
return;
}
c = h2i(*str++) << 4;
if (*str == 0) {
return;
}
c |= h2i(*str++);
*tmp++ = c;
memmove(tmp, str, strlen(str));
tmp[strlen(str)] = 0;
}
}
struct iscsi_url *
iscsi_parse_url(struct iscsi_context *iscsi, const char *url, int full)
{
struct iscsi_url *iscsi_url;
char str[MAX_STRING_SIZE+1];
char *portal;
char *user = NULL;
char *passwd = NULL;
char *target_user = NULL;
char *target_passwd = NULL;
char *usn = NULL;
char *target = NULL;
char *lun;
char *tmp;
int l = 0;
#ifdef HAVE_LINUX_ISER
int is_iser = 0;
#endif
if (strncmp(url, "iscsi://", 8)
#ifdef HAVE_LINUX_ISER
&& strncmp(url, "iser://", 7)
#endif
) {
if (full) {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI URL must "
"be of the form: %s",
url, ISCSI_URL_SYNTAX);
} else {
iscsi_set_error(iscsi, "Invalid URL %s\niSCSI Portal "
"URL must be of the form: %s",
url, ISCSI_PORTAL_URL_SYNTAX);
}
return NULL;
}
#ifdef HAVE_LINUX_ISER
if (!strncmp(url, "iser://", 7)) {
is_iser = 1;
strncpy(str, url + 7, MAX_STRING_SIZE);
}
#endif
if (!strncmp(url, "iscsi://", 8)) {
strncpy(str, url + 8, MAX_STRING_SIZE);
}
portal = str;
user = getenv("LIBISCSI_CHAP_USERNAME");
passwd = getenv("LIBISCSI_CHAP_PASSWORD");
target_user = getenv("LIBISCSI_CHAP_TARGET_USERNAME");
target_passwd = getenv("LIBISCSI_CHAP_TARGET_PASSWORD");
tmp = strchr(portal, '?');
if (tmp) {
*tmp++ = 0;
while (tmp && *tmp) {
char *next = strchr(tmp, '&');
char *key, *value;
if (next != NULL) {
*next++ = 0;
}
key = tmp;
value = strchr(key, '=');
if (value != NULL) {
*value++ = 0;
}
if (!strcmp(key, "auth")) {
if (!strcmp(value, "md5")) {
iscsi->chap_auth = ISCSI_CHAP_MD5;
} else if (!strcmp(value, "sha1")) {
iscsi->chap_auth = ISCSI_CHAP_SHA_1;
} else if (!strcmp(value, "sha-256")) {
iscsi->chap_auth = ISCSI_CHAP_SHA_256;
} else if (!strcmp(value, "sha3-256")) {
iscsi->chap_auth = ISCSI_CHAP_SHA3_256;
} else {
iscsi_set_error(iscsi,
"Invalid argument for auth: %s", value);
return NULL;
}
}
if (!strcmp(key, "header_digest")) {
if (!strcmp(value, "crc32c")) {
iscsi_set_header_digest(
iscsi, ISCSI_HEADER_DIGEST_CRC32C);
} else if (!strcmp(value, "none")) {
iscsi_set_header_digest(
iscsi, ISCSI_HEADER_DIGEST_NONE);
} else {
iscsi_set_error(iscsi,
"Invalid URL argument for header_digest: %s", value);
return NULL;
}
}
if (!strcmp(key, "data_digest")) {
if (!strcmp(value, "crc32c")) {
iscsi_set_data_digest(
iscsi, ISCSI_DATA_DIGEST_CRC32C);
} else if (!strcmp(value, "none")) {
iscsi_set_data_digest(
iscsi, ISCSI_DATA_DIGEST_NONE);
} else {
iscsi_set_error(iscsi,
"Invalid URL argument for data_digest: %s", value);
return NULL;
}
}
if (!strcmp(key, "target_user")) {
target_user = value;
} else if (!strcmp(key, "target_password")) {
target_passwd = value;
#ifdef HAVE_LINUX_ISER
} else if (!strcmp(key, "iser")) {
is_iser = 1;
} else if (!strcmp(key, "LIBISCSI_RDMA_ACK_TIMEOUT")) {
iscsi->rdma_ack_timeout = atoi(value);
#endif
}
if (!strcmp(key, "force_usn")) {
usn = value;
}
tmp = next;
}
}
tmp = strchr(portal, '@');
if (tmp != NULL) {
user = portal;
*tmp++ = 0;
portal = tmp;
tmp = strchr(user, '%');
if (tmp == NULL) {
tmp = strchr(user, ':');
}
if (tmp != NULL) {
*tmp++ = 0;
passwd = tmp;
}
}
if (full) {
target = strchr(portal, '/');
if (target == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not "
"parse '<target-iqn>'\niSCSI URL must be of "
"the form: %s",
url, ISCSI_URL_SYNTAX);
return NULL;
}
*target++ = 0;
if (*target == 0) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not "
"parse <target-iqn>\niSCSI URL must be of the "
"form: %s",
url, ISCSI_URL_SYNTAX);
return NULL;
}
lun = strchr(target, '/');
if (lun == NULL) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not "
"parse <lun>\niSCSI URL must be of the form: "
"%s",
url, ISCSI_URL_SYNTAX);
return NULL;
}
*lun++ = 0;
l = strtol(lun, &tmp, 10);
if (*lun == 0 || *tmp != 0) {
iscsi_set_error(iscsi, "Invalid URL %s\nCould not "
"parse <lun>\niSCSI URL must be of the form: "
"%s",
url, ISCSI_URL_SYNTAX);
return NULL;
}
} else {
tmp=strchr(portal,'/');
if (tmp) {
*tmp=0;
}
}
if (iscsi != NULL) {
iscsi_url = iscsi_malloc(iscsi, sizeof(struct iscsi_url));
} else {
iscsi_url = malloc(sizeof(struct iscsi_url));
}
if (iscsi_url == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: Failed to allocate "
"iscsi_url structure");
return NULL;
}
memset(iscsi_url, 0, sizeof(struct iscsi_url));
iscsi_url->iscsi= iscsi;
strncpy(iscsi_url->portal,portal,MAX_STRING_SIZE);
if (user && passwd && user[0] && passwd[0]) {
strncpy(iscsi_url->user, user, MAX_STRING_SIZE);
strncpy(iscsi_url->passwd, passwd, MAX_STRING_SIZE);
/* if we do not have normal CHAP, that means we do not have
* bidirectional either.
*/
if (target_user && target_passwd && target_user[0] && target_passwd[0]) {
strncpy(iscsi_url->target_user, target_user, MAX_STRING_SIZE);
strncpy(iscsi_url->target_passwd, target_passwd, MAX_STRING_SIZE);
}
}
#ifdef HAVE_LINUX_ISER
if (iscsi) {
if (is_iser) {
if (iscsi_init_transport(iscsi, ISER_TRANSPORT))
iscsi_set_error(iscsi, "Cannot set transport to iSER");
}
}
iscsi_url->transport = is_iser;
#endif
if (full) {
strncpy(iscsi_url->target, target, MAX_STRING_SIZE);
iscsi_url->lun = l;
}
iscsi_decode_url_string(&iscsi_url->target[0]);
/* NOTE: iscsi is allowed to be NULL. Especially qemu does call us with iscsi == NULL.
* If we receive iscsi != NULL we apply the parsed settings to the context. */
if (iscsi) {
iscsi_set_targetname(iscsi, iscsi_url->target);
iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user, iscsi_url->passwd);
iscsi_set_target_username_pwd(iscsi, iscsi_url->target_user, iscsi_url->target_passwd);
if (usn) {
iscsi_set_unit_serial_number(iscsi, usn);
}
}
return iscsi_url;
}
struct iscsi_url *
iscsi_parse_full_url(struct iscsi_context *iscsi, const char *url)
{
return iscsi_parse_url(iscsi,url,1);
}
struct iscsi_url *
iscsi_parse_portal_url(struct iscsi_context *iscsi, const char *url)
{
return iscsi_parse_url(iscsi,url,0);
}
void
iscsi_destroy_url(struct iscsi_url *iscsi_url)
{
struct iscsi_context *iscsi = iscsi_url->iscsi;
memset(iscsi_url, 0, sizeof(struct iscsi_url));
if (iscsi != NULL)
iscsi_free(iscsi, iscsi_url);
else
free(iscsi_url);
}
int
iscsi_set_initiator_username_pwd(struct iscsi_context *iscsi,
const char *user, const char *passwd)
{
if (!user || !passwd || !user[0] || !passwd[0]) {
iscsi->user[0] = 0;
iscsi->passwd[0] = 0;
return 0;
}
strncpy(iscsi->user,user,MAX_STRING_SIZE);
strncpy(iscsi->passwd,passwd,MAX_STRING_SIZE);
return 0;
}
int
iscsi_set_target_username_pwd(struct iscsi_context *iscsi,
const char *user, const char *passwd)
{
if (!user || !passwd || !user[0] || !passwd[0]) {
iscsi->target_user[0] = 0;
iscsi->target_passwd[0] = 0;
return 0;
}
strncpy(iscsi->target_user, user, MAX_STRING_SIZE);
strncpy(iscsi->target_passwd, passwd, MAX_STRING_SIZE);
return 0;
}
int
iscsi_set_immediate_data(struct iscsi_context *iscsi, enum iscsi_immediate_data immediate_data)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when trying to set immediate_data");
return -1;
}
iscsi->want_immediate_data = immediate_data;
iscsi->use_immediate_data = immediate_data;
return 0;
}
int
iscsi_set_initial_r2t(struct iscsi_context *iscsi, enum iscsi_initial_r2t initial_r2t)
{
if (iscsi->is_loggedin != 0) {
iscsi_set_error(iscsi, "Already logged in when trying to set initial_r2t");
return -1;
}
iscsi->want_initial_r2t = initial_r2t;
return 0;
}
int
iscsi_set_timeout(struct iscsi_context *iscsi, int timeout)
{
iscsi->scsi_timeout = timeout;
return 0;
}
void
iscsi_set_fd_dup_cb(struct iscsi_context *iscsi,
void (*cb)(struct iscsi_context *iscsi, void *opaque),
void *opaque)
{
iscsi->fd_dup_cb = cb;
iscsi->fd_dup_opaque = opaque;
}
enum iscsi_chap_auth
iscsi_get_auth(struct iscsi_context *iscsi)
{
return iscsi->chap_auth;
}
void
iscsi_set_auth(struct iscsi_context *iscsi, enum iscsi_chap_auth auth)
{
iscsi->chap_auth = auth;
}