Blame usr/initiator_common.c

Packit eace71
/*
Packit eace71
 * Common code for setting up discovery and normal sessions.
Packit eace71
 *
Packit eace71
 * Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
Packit eace71
 * Copyright (C) 2006 - 2009 Mike Christie
Packit eace71
 * Copyright (C) 2006 - 2009 Red Hat, Inc. All rights reserved.
Packit eace71
 * maintained by open-iscsi@googlegroups.com
Packit eace71
 *
Packit eace71
 * This program is free software; you can redistribute it and/or modify
Packit eace71
 * it under the terms of the GNU General Public License as published
Packit eace71
 * by the Free Software Foundation; either version 2 of the License, or
Packit eace71
 * (at your option) any later version.
Packit eace71
 *
Packit eace71
 * This program is distributed in the hope that it will be useful, but
Packit eace71
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit eace71
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit eace71
 * General Public License for more details.
Packit eace71
 *
Packit eace71
 * See the file COPYING included with this distribution for more details.
Packit eace71
 */
Packit eace71
Packit eace71
#include <string.h>
Packit eace71
#include <stdio.h>
Packit eace71
#include <stdlib.h>
Packit eace71
#include <errno.h>
Packit eace71
#include <dirent.h>
Packit eace71
#include <libmount/libmount.h>
Packit eace71
Packit eace71
#include "initiator.h"
Packit eace71
#include "transport.h"
Packit eace71
#include "iscsid.h"
Packit eace71
#include "iscsi_ipc.h"
Packit eace71
#include "log.h"
Packit eace71
#include "iscsi_sysfs.h"
Packit eace71
#include "iscsi_settings.h"
Packit eace71
#include "iface.h"
Packit eace71
#include "host.h"
Packit eace71
#include "sysdeps.h"
Packit eace71
#include "iscsi_err.h"
Packit eace71
#include "iscsi_net_util.h"
Packit eace71
Packit eace71
struct iscsi_session *session_find_by_sid(uint32_t sid)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t;
Packit eace71
	struct iscsi_session *session;
Packit eace71
Packit eace71
	list_for_each_entry(t, &transports, list) {
Packit eace71
		list_for_each_entry(session, &t->sessions, list) {
Packit eace71
			if (session->id == sid)
Packit eace71
				return session;
Packit eace71
		}
Packit eace71
	}
Packit eace71
	return NULL;
Packit eace71
}
Packit eace71
Packit eace71
const static unsigned int align_32_down(unsigned int param)
Packit eace71
{
Packit eace71
	return param & ~0x3;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_setup_authentication(struct iscsi_session *session,
Packit eace71
			       struct iscsi_auth_config *auth_cfg)
Packit eace71
{
Packit eace71
	/* if we have any incoming credentials, we insist on authenticating
Packit eace71
	 * the target or not logging in at all
Packit eace71
	 */
Packit eace71
	if (auth_cfg->username_in[0] || auth_cfg->password_in_length) {
Packit eace71
		/* sanity check the config */
Packit eace71
		if (auth_cfg->password_length == 0) {
Packit eace71
			log_warning("CHAP configuration has incoming "
Packit eace71
				    "authentication credentials but has no "
Packit eace71
				    "outgoing credentials configured.");
Packit eace71
			return EINVAL;
Packit eace71
		}
Packit eace71
		session->bidirectional_auth = 1;
Packit eace71
	} else {
Packit eace71
		/* no or 1-way authentication */
Packit eace71
		session->bidirectional_auth = 0;
Packit eace71
	}
Packit eace71
Packit eace71
	/* copy in whatever credentials we have */
Packit eace71
	strlcpy(session->username, auth_cfg->username,
Packit eace71
		sizeof (session->username));
Packit eace71
	session->username[sizeof (session->username) - 1] = '\0';
Packit eace71
	if ((session->password_length = auth_cfg->password_length))
Packit eace71
		memcpy(session->password, auth_cfg->password,
Packit eace71
		       session->password_length);
Packit eace71
Packit eace71
	strlcpy(session->username_in, auth_cfg->username_in,
Packit eace71
		sizeof (session->username_in));
Packit eace71
	session->username_in[sizeof (session->username_in) - 1] = '\0';
Packit eace71
	if ((session->password_in_length =
Packit eace71
	     auth_cfg->password_in_length))
Packit eace71
		memcpy(session->password_in, auth_cfg->password_in,
Packit eace71
		       session->password_in_length);
Packit eace71
Packit eace71
	if (session->password_length || session->password_in_length) {
Packit eace71
		/* setup the auth buffers */
Packit eace71
		session->auth_buffers[0].address = &session->auth_client_block;
Packit eace71
		session->auth_buffers[0].length =
Packit eace71
		    sizeof (session->auth_client_block);
Packit eace71
		session->auth_buffers[1].address =
Packit eace71
		    &session->auth_recv_string_block;
Packit eace71
		session->auth_buffers[1].length =
Packit eace71
		    sizeof (session->auth_recv_string_block);
Packit eace71
Packit eace71
		session->auth_buffers[2].address =
Packit eace71
		    &session->auth_send_string_block;
Packit eace71
		session->auth_buffers[2].length =
Packit eace71
		    sizeof (session->auth_send_string_block);
Packit eace71
Packit eace71
		session->auth_buffers[3].address =
Packit eace71
		    &session->auth_recv_binary_block;
Packit eace71
		session->auth_buffers[3].length =
Packit eace71
		    sizeof (session->auth_recv_binary_block);
Packit eace71
Packit eace71
		session->auth_buffers[4].address =
Packit eace71
		    &session->auth_send_binary_block;
Packit eace71
		session->auth_buffers[4].length =
Packit eace71
		    sizeof (session->auth_send_binary_block);
Packit eace71
Packit eace71
		session->num_auth_buffers = 5;
Packit eace71
		log_debug(6, "authentication setup complete...");
Packit eace71
	} else {
Packit eace71
		session->num_auth_buffers = 0;
Packit eace71
		log_debug(6, "no authentication configured...");
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
void
Packit eace71
iscsi_copy_operational_params(struct iscsi_conn *conn,
Packit eace71
			struct iscsi_session_operational_config *session_conf,
Packit eace71
			struct iscsi_conn_operational_config *conn_conf)
Packit eace71
{
Packit eace71
	struct iscsi_session *session = conn->session;
Packit eace71
	struct iscsi_transport *t = session->t;
Packit eace71
Packit eace71
	conn->hdrdgst_en = conn_conf->HeaderDigest;
Packit eace71
	conn->datadgst_en = conn_conf->DataDigest;
Packit eace71
Packit eace71
	conn->max_recv_dlength =
Packit eace71
			align_32_down(conn_conf->MaxRecvDataSegmentLength);
Packit eace71
	if (conn->max_recv_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
Packit eace71
	    conn->max_recv_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
Packit eace71
		log_error("Invalid iscsi.MaxRecvDataSegmentLength. Must be "
Packit eace71
			 "within %u and %u. Setting to %u",
Packit eace71
			  ISCSI_MIN_MAX_RECV_SEG_LEN,
Packit eace71
			  ISCSI_MAX_MAX_RECV_SEG_LEN,
Packit eace71
			  DEF_INI_MAX_RECV_SEG_LEN);
Packit eace71
		conn_conf->MaxRecvDataSegmentLength =
Packit eace71
						DEF_INI_MAX_RECV_SEG_LEN;
Packit eace71
		conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN;
Packit eace71
	}
Packit eace71
Packit eace71
	/* zero indicates to use the target's value */
Packit eace71
	conn->max_xmit_dlength =
Packit eace71
			align_32_down(conn_conf->MaxXmitDataSegmentLength);
Packit eace71
	if (conn->max_xmit_dlength == 0)
Packit eace71
		conn->max_xmit_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
Packit eace71
	if (conn->max_xmit_dlength < ISCSI_MIN_MAX_RECV_SEG_LEN ||
Packit eace71
	    conn->max_xmit_dlength > ISCSI_MAX_MAX_RECV_SEG_LEN) {
Packit eace71
		log_error("Invalid iscsi.MaxXmitDataSegmentLength. Must be "
Packit eace71
			 "within %u and %u. Setting to %u",
Packit eace71
			  ISCSI_MIN_MAX_RECV_SEG_LEN,
Packit eace71
			  ISCSI_MAX_MAX_RECV_SEG_LEN,
Packit eace71
			  DEF_INI_MAX_RECV_SEG_LEN);
Packit eace71
		conn_conf->MaxXmitDataSegmentLength =
Packit eace71
						DEF_INI_MAX_RECV_SEG_LEN;
Packit eace71
		conn->max_xmit_dlength = DEF_INI_MAX_RECV_SEG_LEN;
Packit eace71
	}
Packit eace71
Packit eace71
	/* session's operational parameters */
Packit eace71
	session->initial_r2t_en = session_conf->InitialR2T;
Packit eace71
	session->max_r2t = session_conf->MaxOutstandingR2T;
Packit eace71
	session->imm_data_en = session_conf->ImmediateData;
Packit eace71
	session->first_burst = align_32_down(session_conf->FirstBurstLength);
Packit eace71
	/*
Packit eace71
	 * some targets like netapp fail the login if sent bad first_burst
Packit eace71
	 * and max_burst lens, even when immediate data=no and
Packit eace71
	 * initial r2t = Yes, so we always check the user values.
Packit eace71
	 */
Packit eace71
	if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN ||
Packit eace71
	    session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) {
Packit eace71
		log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
Packit eace71
			 "within %u and %u. Setting to %u",
Packit eace71
			  session->first_burst,
Packit eace71
			  ISCSI_MIN_FIRST_BURST_LEN,
Packit eace71
			  ISCSI_MAX_FIRST_BURST_LEN,
Packit eace71
			  DEF_INI_FIRST_BURST_LEN);
Packit eace71
		session_conf->FirstBurstLength = DEF_INI_FIRST_BURST_LEN;
Packit eace71
		session->first_burst = DEF_INI_FIRST_BURST_LEN;
Packit eace71
	}
Packit eace71
Packit eace71
	session->max_burst = align_32_down(session_conf->MaxBurstLength);
Packit eace71
	if (session->max_burst < ISCSI_MIN_MAX_BURST_LEN ||
Packit eace71
	    session->max_burst > ISCSI_MAX_MAX_BURST_LEN) {
Packit eace71
		log_error("Invalid iscsi.MaxBurstLength of %u. Must be "
Packit eace71
			  "within %u and %u. Setting to %u",
Packit eace71
			   session->max_burst, ISCSI_MIN_MAX_BURST_LEN,
Packit eace71
			   ISCSI_MAX_MAX_BURST_LEN, DEF_INI_MAX_BURST_LEN);
Packit eace71
		session_conf->MaxBurstLength = DEF_INI_MAX_BURST_LEN;
Packit eace71
		session->max_burst = DEF_INI_MAX_BURST_LEN;
Packit eace71
	}
Packit eace71
Packit eace71
	if (session->first_burst > session->max_burst) {
Packit eace71
		log_error("Invalid iscsi.FirstBurstLength of %u. Must be "
Packit eace71
			  "less than iscsi.MaxBurstLength. Setting to %u",
Packit eace71
			   session->first_burst, session->max_burst);
Packit eace71
		session_conf->FirstBurstLength = session->max_burst;
Packit eace71
		session->first_burst = session->max_burst;
Packit eace71
	}
Packit eace71
Packit eace71
	session->def_time2wait = session_conf->DefaultTime2Wait;
Packit eace71
	session->def_time2retain = session_conf->DefaultTime2Retain;
Packit eace71
	session->erl = session_conf->ERL;
Packit eace71
Packit eace71
	if (session->type == ISCSI_SESSION_TYPE_DISCOVERY) {
Packit eace71
		/*
Packit eace71
		 * Right now, we only support 8K max for kernel based
Packit eace71
		 * sendtargets discovery, because the recv pdu buffers are
Packit eace71
		 * limited to this size.
Packit eace71
		 */
Packit eace71
		if ((t->caps & CAP_TEXT_NEGO) &&
Packit eace71
		     conn->max_recv_dlength > ISCSI_DEF_MAX_RECV_SEG_LEN)
Packit eace71
			conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
Packit eace71
Packit eace71
		/* We do not support discovery sessions with digests */
Packit eace71
		conn->hdrdgst_en = ISCSI_DIGEST_NONE;
Packit eace71
		conn->datadgst_en = ISCSI_DIGEST_NONE;
Packit eace71
	}
Packit eace71
Packit eace71
	if (t->template->create_conn)
Packit eace71
		t->template->create_conn(conn);
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_setup_portal(struct iscsi_conn *conn, char *address, int port)
Packit eace71
{
Packit eace71
	char serv[NI_MAXSERV];
Packit eace71
Packit eace71
	sprintf(serv, "%d", port);
Packit eace71
	if (resolve_address(address, serv, &conn->saddr)) {
Packit eace71
		log_error("cannot resolve host name %s", address);
Packit eace71
		return ISCSI_ERR_TRANS;
Packit eace71
	}
Packit eace71
	conn->failback_saddr = conn->saddr;
Packit eace71
Packit eace71
	getnameinfo((struct sockaddr *)&conn->saddr, sizeof(conn->saddr),
Packit eace71
		    conn->host, sizeof(conn->host), NULL, 0, NI_NUMERICHOST);
Packit eace71
	log_debug(4, "resolved %s to %s", address, conn->host);
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static int host_set_param(struct iscsi_transport *t,
Packit eace71
		   uint32_t host_no, int param, char *value,
Packit eace71
		   int type)
Packit eace71
{
Packit eace71
	int rc;
Packit eace71
Packit eace71
	rc = ipc->set_host_param(t->handle, host_no, param, value, type);
Packit eace71
	/* 2.6.20 and below returns EINVAL */
Packit eace71
	if (rc && rc != -ENOSYS && rc != -EINVAL) {
Packit eace71
		log_error("can't set operational parameter %d for "
Packit eace71
			  "host %d, retcode %d (%d)", param, host_no,
Packit eace71
			  rc, errno);
Packit eace71
		return ISCSI_ERR_INVAL;
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static void print_param_value(enum iscsi_param param, void *value, int type)
Packit eace71
{
Packit eace71
	log_debug(3, "set operational parameter %d to:", param);
Packit eace71
Packit eace71
	if (type == ISCSI_STRING)
Packit eace71
		log_debug(3, "%s", value ? (char *)value : "NULL");
Packit eace71
	else
Packit eace71
		log_debug(3, "%u", *(uint32_t *)value);
Packit eace71
}
Packit eace71
Packit eace71
#define MAX_HOST_PARAMS 2
Packit eace71
Packit eace71
int iscsi_host_set_params(struct iscsi_session *session)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t = session->t;
Packit eace71
	int i;
Packit eace71
	struct hostparam {
Packit eace71
		int param;
Packit eace71
		int type;
Packit eace71
		void *value;
Packit eace71
	} hosttbl[MAX_HOST_PARAMS] = {
Packit eace71
		{
Packit eace71
			.param = ISCSI_HOST_PARAM_NETDEV_NAME,
Packit eace71
			.value = session->nrec.iface.netdev,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_HOST_PARAM_HWADDRESS,
Packit eace71
			.value = session->nrec.iface.hwaddress,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
		},
Packit eace71
	};
Packit eace71
Packit eace71
	for (i = 0; i < MAX_HOST_PARAMS; i++) {
Packit eace71
		if (host_set_param(t, session->hostno,
Packit eace71
				   hosttbl[i].param, hosttbl[i].value,
Packit eace71
				   hosttbl[i].type)) {
Packit eace71
			return EPERM;
Packit eace71
		}
Packit eace71
Packit eace71
		print_param_value(hosttbl[i].param, hosttbl[i].value,
Packit eace71
				  hosttbl[i].type);
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static inline void iscsi_session_clear_param(struct iscsi_session *session,
Packit eace71
					     int param)
Packit eace71
{
Packit eace71
	session->param_mask &= ~(1ULL << param);
Packit eace71
}
Packit eace71
Packit eace71
void iscsi_session_init_params(struct iscsi_session *session)
Packit eace71
{
Packit eace71
	session->param_mask = ~0ULL;
Packit eace71
	if (!(session->t->caps & CAP_MULTI_R2T))
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_MAX_R2T);
Packit eace71
	if (!(session->t->caps & CAP_HDRDGST))
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_HDRDGST_EN); 
Packit eace71
	if (!(session->t->caps & CAP_DATADGST))
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_DATADGST_EN); 
Packit eace71
	if (!(session->t->caps & CAP_MARKERS)) {
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_IFMARKER_EN);
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_OFMARKER_EN);
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
#define MAX_SESSION_NEG_PARAMS 16
Packit eace71
Packit eace71
int iscsi_session_set_neg_params(struct iscsi_conn *conn)
Packit eace71
{
Packit eace71
	struct iscsi_session *session = conn->session;
Packit eace71
	int i, rc;
Packit eace71
	uint32_t zero = 0;
Packit eace71
	struct connparam {
Packit eace71
		int param;
Packit eace71
		int type;
Packit eace71
		void *value;
Packit eace71
		int conn_only;
Packit eace71
	} conntbl[MAX_SESSION_NEG_PARAMS] = {
Packit eace71
		{
Packit eace71
			.param = ISCSI_PARAM_MAX_RECV_DLENGTH,
Packit eace71
			.value = &conn->max_recv_dlength,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_MAX_XMIT_DLENGTH,
Packit eace71
			.value = &conn->max_xmit_dlength,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_HDRDGST_EN,
Packit eace71
			.value = &conn->hdrdgst_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_DATADGST_EN,
Packit eace71
			.value = &conn->datadgst_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_INITIAL_R2T_EN,
Packit eace71
			.value = &session->initial_r2t_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_MAX_R2T,
Packit eace71
			.value = &session->max_r2t,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_IMM_DATA_EN,
Packit eace71
			.value = &session->imm_data_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_FIRST_BURST,
Packit eace71
			.value = &session->first_burst,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_MAX_BURST,
Packit eace71
			.value = &session->max_burst,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PDU_INORDER_EN,
Packit eace71
			.value = &session->pdu_inorder_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param =ISCSI_PARAM_DATASEQ_INORDER_EN,
Packit eace71
			.value = &session->dataseq_inorder_en,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_ERL,
Packit eace71
			.value = &zero, /* FIXME: session->erl */
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_IFMARKER_EN,
Packit eace71
			.value = &zero,/* FIXME: session->ifmarker_en */
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_OFMARKER_EN,
Packit eace71
			.value = &zero,/* FIXME: session->ofmarker_en */
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_EXP_STATSN,
Packit eace71
			.value = &conn->exp_statsn,
Packit eace71
			.type = ISCSI_UINT,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_TPGT,
Packit eace71
			.value = &session->portal_group_tag,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		},
Packit eace71
	};
Packit eace71
Packit eace71
	iscsi_session_init_params(session);
Packit eace71
Packit eace71
	/* Entered full-feature phase! */
Packit eace71
	for (i = 0; i < MAX_SESSION_NEG_PARAMS; i++) {
Packit eace71
		if (conn->id != 0 && !conntbl[i].conn_only)
Packit eace71
			continue;
Packit eace71
Packit eace71
		if (!(session->param_mask & (1ULL << conntbl[i].param)))
Packit eace71
			continue;
Packit eace71
Packit eace71
		rc = ipc->set_param(session->t->handle, session->id,
Packit eace71
				   conn->id, conntbl[i].param, conntbl[i].value,
Packit eace71
				   conntbl[i].type);
Packit eace71
		if (rc && rc != -ENOSYS) {
Packit eace71
			log_error("can't set operational parameter %d for "
Packit eace71
				  "connection %d:%d, retcode %d (%d)",
Packit eace71
				  conntbl[i].param, session->id, conn->id,
Packit eace71
				  rc, errno);
Packit eace71
			return EPERM;
Packit eace71
		}
Packit eace71
Packit eace71
		print_param_value(conntbl[i].param, conntbl[i].value,
Packit eace71
				  conntbl[i].type);
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
#define MAX_SESSION_PARAMS 20
Packit eace71
Packit eace71
int iscsi_session_set_params(struct iscsi_conn *conn)
Packit eace71
{
Packit eace71
	struct iscsi_session *session = conn->session;
Packit eace71
	int i, rc;
Packit eace71
	struct connparam {
Packit eace71
		int param;
Packit eace71
		int type;
Packit eace71
		void *value;
Packit eace71
		int conn_only;
Packit eace71
	} conntbl[MAX_SESSION_PARAMS] = {
Packit eace71
		{
Packit eace71
			.param = ISCSI_PARAM_TARGET_NAME,
Packit eace71
			.conn_only = 0,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.value = session->target_name,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PERSISTENT_ADDRESS,
Packit eace71
			.value = session->nrec.conn[conn->id].address,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PERSISTENT_PORT,
Packit eace71
			.value = &session->nrec.conn[conn->id].port,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_SESS_RECOVERY_TMO,
Packit eace71
			.value = &session->replacement_timeout,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_USERNAME,
Packit eace71
			.value = session->username,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_USERNAME_IN,
Packit eace71
			.value = session->username_in,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PASSWORD,
Packit eace71
			.value = session->password,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PASSWORD_IN,
Packit eace71
			.value = session->password_in,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_FAST_ABORT,
Packit eace71
			.value = &session->fast_abort,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_ABORT_TMO,
Packit eace71
			.value = &session->abort_timeout,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_LU_RESET_TMO,
Packit eace71
			.value = &session->lu_reset_timeout,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_TGT_RESET_TMO,
Packit eace71
			.value = &session->tgt_reset_timeout,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_PING_TMO,
Packit eace71
			.value = &conn->noop_out_timeout,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_RECV_TMO,
Packit eace71
			.value = &conn->noop_out_interval,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 1,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_IFACE_NAME,
Packit eace71
			.value = session->nrec.iface.name,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_INITIATOR_NAME,
Packit eace71
			.value = session->initiator_name,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_BOOT_ROOT,
Packit eace71
			.value = session->nrec.session.boot_root,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_BOOT_NIC,
Packit eace71
			.value = session->nrec.session.boot_nic,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_BOOT_TARGET,
Packit eace71
			.value = session->nrec.session.boot_target,
Packit eace71
			.type = ISCSI_STRING,
Packit eace71
			.conn_only = 0,
Packit eace71
		}, {
Packit eace71
			.param = ISCSI_PARAM_DISCOVERY_SESS,
Packit eace71
			.value = &session->type,
Packit eace71
			.type = ISCSI_INT,
Packit eace71
			.conn_only = 0,
Packit eace71
		},
Packit eace71
	};
Packit eace71
Packit eace71
	iscsi_session_init_params(session);
Packit eace71
Packit eace71
	/* some llds will send nops internally */
Packit eace71
	if (!iscsi_sysfs_session_supports_nop(session->id)) {
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_PING_TMO); 
Packit eace71
		iscsi_session_clear_param(session, ISCSI_PARAM_RECV_TMO);
Packit eace71
	}
Packit eace71
Packit eace71
	/* Entered full-feature phase! */
Packit eace71
	for (i = 0; i < MAX_SESSION_PARAMS; i++) {
Packit eace71
		if (conn->id != 0 && !conntbl[i].conn_only)
Packit eace71
			continue;
Packit eace71
Packit eace71
		if (!(session->param_mask & (1ULL << conntbl[i].param)))
Packit eace71
			continue;
Packit eace71
Packit eace71
		rc = ipc->set_param(session->t->handle, session->id,
Packit eace71
				   conn->id, conntbl[i].param, conntbl[i].value,
Packit eace71
				   conntbl[i].type);
Packit eace71
		if (rc && rc != -ENOSYS) {
Packit eace71
			log_error("can't set operational parameter %d for "
Packit eace71
				  "connection %d:%d, retcode %d (%d)",
Packit eace71
				  conntbl[i].param, session->id, conn->id,
Packit eace71
				  rc, errno);
Packit eace71
			return EPERM;
Packit eace71
		}
Packit eace71
Packit eace71
		if (rc == -ENOSYS) {
Packit eace71
			switch (conntbl[i].param) {
Packit eace71
			case ISCSI_PARAM_PING_TMO:
Packit eace71
				/*
Packit eace71
				 * older kernels may not support nops
Packit eace71
				 * in kernel
Packit eace71
				 */
Packit eace71
				conn->userspace_nop = 1;
Packit eace71
				break;
Packit eace71
#if 0
Packit eace71
TODO handle this
Packit eace71
			case ISCSI_PARAM_INITIATOR_NAME:
Packit eace71
				/* use host level one instead */
Packit eace71
				hosttbl[ISCSI_HOST_PARAM_INITIATOR_NAME].set = 1;
Packit eace71
				break;
Packit eace71
#endif
Packit eace71
			}
Packit eace71
		}
Packit eace71
Packit eace71
		print_param_value(conntbl[i].param, conntbl[i].value,
Packit eace71
				  conntbl[i].type);
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_set_net_config(struct iscsi_transport *t, iscsi_session_t *session,
Packit eace71
			 struct iface_rec *iface)
Packit eace71
{
Packit eace71
	if (t->template->set_net_config) {
Packit eace71
		/* uip needs the netdev name */
Packit eace71
		struct host_info hinfo;
Packit eace71
		int hostno, rc;
Packit eace71
Packit eace71
		/* this assumes that the netdev or hw address is going to be
Packit eace71
		   set */
Packit eace71
		hostno = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
Packit eace71
		if (rc) {
Packit eace71
			log_debug(4, "Couldn't get host no.");
Packit eace71
			return rc;
Packit eace71
		}
Packit eace71
Packit eace71
		/* uip needs the netdev name */
Packit eace71
		if (!strlen(iface->netdev)) {
Packit eace71
			memset(&hinfo, 0, sizeof(hinfo));
Packit eace71
			hinfo.host_no = hostno;
Packit eace71
			iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
Packit eace71
			strcpy(iface->netdev, hinfo.iface.netdev);
Packit eace71
		}
Packit eace71
Packit eace71
		return t->template->set_net_config(t, iface, session);
Packit eace71
	}
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
int iscsi_host_set_net_params(struct iface_rec *iface,
Packit eace71
			      struct iscsi_session *session)
Packit eace71
{
Packit eace71
	struct iscsi_transport *t = session->t;
Packit eace71
	int rc = 0;
Packit eace71
	char *netdev;
Packit eace71
	struct host_info hinfo;
Packit eace71
Packit eace71
	log_debug(3, "setting iface %s, dev %s, set ip %s, hw %s, "
Packit eace71
		  "transport %s.",
Packit eace71
		  iface->name, iface->netdev, iface->ipaddress,
Packit eace71
		  iface->hwaddress, iface->transport_name);
Packit eace71
Packit eace71
	if (!t->template->set_host_ip)
Packit eace71
		return 0;
Packit eace71
Packit eace71
	/* if we need to set the ip addr then set all the iface net settings */
Packit eace71
	if (!iface_is_bound_by_ipaddr(iface)) {
Packit eace71
		if (t->template->set_host_ip == SET_HOST_IP_REQ) {
Packit eace71
			log_warning("Please set the iface.ipaddress for iface "
Packit eace71
				    "%s, then retry the login command.",
Packit eace71
				    iface->name);
Packit eace71
			return ISCSI_ERR_INVAL;
Packit eace71
		} else if (t->template->set_host_ip == SET_HOST_IP_OPT) {
Packit eace71
			log_info("Optional iface.ipaddress for iface %s "
Packit eace71
				 "not set.", iface->name);
Packit eace71
			return 0;
Packit eace71
		} else {
Packit eace71
			return ISCSI_ERR_INVAL;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	/* these type of drivers need the netdev upd */
Packit eace71
	if (strlen(iface->netdev))
Packit eace71
		netdev = iface->netdev;
Packit eace71
	else {
Packit eace71
		memset(&hinfo, 0, sizeof(hinfo));
Packit eace71
		hinfo.host_no = session->hostno;
Packit eace71
		iscsi_sysfs_get_hostinfo_by_host_no(&hinfo);
Packit eace71
Packit eace71
		netdev = hinfo.iface.netdev;
Packit eace71
	}
Packit eace71
Packit eace71
	if (!t->template->no_netdev && net_ifup_netdev(netdev))
Packit eace71
		log_warning("Could not brining up netdev %s. Try running "
Packit eace71
			    "'ifup %s' first if login fails.", netdev, netdev);
Packit eace71
Packit eace71
	rc = iscsi_set_net_config(t, session, iface);
Packit eace71
	if (rc != 0)
Packit eace71
		return rc;
Packit eace71
Packit eace71
	rc = host_set_param(t, session->hostno,
Packit eace71
			    ISCSI_HOST_PARAM_IPADDRESS,
Packit eace71
			    iface->ipaddress, ISCSI_STRING);
Packit eace71
	if (rc)
Packit eace71
		return rc;
Packit eace71
Packit eace71
	if (iface_is_bound_by_netdev(iface)) {
Packit eace71
		rc = host_set_param(t, session->hostno,
Packit eace71
				    ISCSI_HOST_PARAM_NETDEV_NAME,
Packit eace71
				    iface->netdev, ISCSI_STRING);
Packit eace71
		if (rc)
Packit eace71
			return rc;
Packit eace71
	}
Packit eace71
Packit eace71
	if (iface_is_bound_by_hwaddr(iface)) {
Packit eace71
		rc = host_set_param(t, session->hostno,
Packit eace71
				    ISCSI_HOST_PARAM_HWADDRESS,
Packit eace71
				    iface->hwaddress, ISCSI_STRING);
Packit eace71
		if (rc)
Packit eace71
			return rc;
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}