Blame usr/discovery.c

Packit Service 646995
/*
Packit Service 646995
 * iSCSI Discovery
Packit Service 646995
 *
Packit Service 646995
 * Copyright (C) 2002 Cisco Systems, Inc.
Packit Service 646995
 *
Packit Service 646995
 * This program is free software; you can redistribute it and/or modify
Packit Service 646995
 * it under the terms of the GNU General Public License as published
Packit Service 646995
 * by the Free Software Foundation; either version 2 of the License, or
Packit Service 646995
 * (at your option) any later version.
Packit Service 646995
 *
Packit Service 646995
 * This program is distributed in the hope that it will be useful, but
Packit Service 646995
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 646995
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit Service 646995
 * General Public License for more details.
Packit Service 646995
 *
Packit Service 646995
 * See the file COPYING included with this distribution for more details.
Packit Service 646995
 */
Packit Service 646995
Packit Service 646995
#include <stdio.h>
Packit Service 646995
#include <unistd.h>
Packit Service 646995
#include <fcntl.h>
Packit Service 646995
#include <signal.h>
Packit Service 646995
#include <errno.h>
Packit Service 646995
#include <netdb.h>
Packit Service 646995
#include <stdint.h>
Packit Service 646995
#include <stdlib.h>
Packit Service 646995
#include <string.h>
Packit Service 646995
#include <poll.h>
Packit Service 646995
#include <sys/time.h>
Packit Service 646995
#include <sys/param.h>
Packit Service 646995
#include <sys/socket.h>
Packit Service 646995
#include <netinet/in.h>
Packit Service 646995
#include <arpa/inet.h>
Packit Service 646995
Packit Service 646995
#include "local_strings.h"
Packit Service 646995
#include "types.h"
Packit Service 646995
#include "iscsi_proto.h"
Packit Service 646995
#include "initiator.h"
Packit Service 2a7015
#include "config.h"
Packit Service 646995
#include "log.h"
Packit Service 646995
#include "idbm.h"
Packit Service 646995
#include "iscsi_settings.h"
Packit Service 646995
#include "sysdeps.h"
Packit Service 646995
#include "fw_context.h"
Packit Service 646995
#include "iscsid_req.h"
Packit Service 646995
#include "iscsi_util.h"
Packit Service 646995
#include "transport.h"
Packit Service 646995
#include "iscsi_sysfs.h"
Packit Service 646995
#include "iscsi_ipc.h"
Packit Service 646995
#include "iface.h"
Packit Service 646995
#include "iscsi_timer.h"
Packit Service 646995
#include "iscsi_err.h"
Packit Service 2a7015
#ifdef ISNS_ENABLE
Packit Service 646995
/* libisns includes */
Packit Service 646995
#include <libisns/isns.h>
Packit Service 646995
#include <libisns/paths.h>
Packit Service 646995
#include <libisns/message.h>
Packit Service 2a7015
#endif
Packit Service 646995
Packit Service 646995
#ifdef SLP_ENABLE
Packit Service 646995
#include "iscsi-slp-discovery.h"
Packit Service 646995
#endif
Packit Service 646995
Packit Service 646995
#define DISCOVERY_NEED_RECONNECT 0xdead0001
Packit Service 646995
Packit Service 646995
static char initiator_name[TARGET_NAME_MAXLEN + 1];
Packit Service 646995
static char initiator_alias[TARGET_NAME_MAXLEN + 1];
Packit Service 646995
static struct iscsi_ev_context ipc_ev_context;
Packit Service 646995
Packit Service 646995
static int request_initiator_name(int tmo)
Packit Service 646995
{
Packit Service 646995
	int rc;
Packit Service 646995
	iscsiadm_req_t req;
Packit Service 646995
	iscsiadm_rsp_t rsp;
Packit Service 646995
Packit Service 646995
	memset(initiator_name, 0, sizeof(initiator_name));
Packit Service 646995
	initiator_name[0] = '\0';
Packit Service 646995
	memset(initiator_alias, 0, sizeof(initiator_alias));
Packit Service 646995
	initiator_alias[0] = '\0';
Packit Service 646995
Packit Service 646995
	memset(&req, 0, sizeof(req));
Packit Service 646995
	req.command = MGMT_IPC_CONFIG_INAME;
Packit Service 646995
Packit Service 646995
	rc = iscsid_exec_req(&req, &rsp, 1, tmo);
Packit Service 646995
	if (rc)
Packit Service 646995
		return rc;
Packit Service 646995
Packit Service 646995
	if (rsp.u.config.var[0] != '\0')
Packit Service 646995
		strcpy(initiator_name, rsp.u.config.var);
Packit Service 646995
Packit Service 646995
	memset(&req, 0, sizeof(req));
Packit Service 646995
	req.command = MGMT_IPC_CONFIG_IALIAS;
Packit Service 646995
Packit Service 646995
	rc = iscsid_exec_req(&req, &rsp, 0, tmo);
Packit Service 646995
	if (rc)
Packit Service 646995
		/* alias is optional so return ok */
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
	if (rsp.u.config.var[0] != '\0')
Packit Service 646995
		strcpy(initiator_alias, rsp.u.config.var);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 2a7015
#ifdef ISNS_ENABLE
Packit Service 646995
void discovery_isns_free_servername(void)
Packit Service 646995
{
Packit Service 646995
	if (isns_config.ic_server_name)
Packit Service 646995
		free(isns_config.ic_server_name);
Packit Service 646995
	isns_config.ic_server_name = NULL;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int discovery_isns_set_servername(char *address, int port)
Packit Service 646995
{
Packit Service 646995
	char *server;
Packit Service 646995
	int len;
Packit Service 646995
Packit Service 646995
	if (port > USHRT_MAX) {
Packit Service 646995
		log_error("Invalid port %d", port);
Packit Service 646995
		return ISCSI_ERR_INVAL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* 5 for port and 1 for colon and 1 for null */
Packit Service 646995
	len = strlen(address) + 7;
Packit Service 646995
	server = calloc(1, len);
Packit Service 646995
	if (!server)
Packit Service 646995
		return ISCSI_ERR_NOMEM;
Packit Service 646995
Packit Service 646995
	snprintf(server, len, "%s:%d", address, port);
Packit Service 646995
	isns_assign_string(&isns_config.ic_server_name, server);
Packit Service 646995
	free(server);
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int discovery_isns_query(struct discovery_rec *drec, const char *iname,
Packit Service 646995
			 const char *targetname, struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	isns_attr_list_t key_attrs = ISNS_ATTR_LIST_INIT;
Packit Service 646995
	isns_object_list_t objects = ISNS_OBJECT_LIST_INIT;
Packit Service 646995
	isns_source_t *source;
Packit Service 646995
	isns_simple_t *qry;
Packit Service 646995
	isns_client_t *clnt;
Packit Service 646995
	uint32_t status;
Packit Service 646995
	int rc;
Packit Service 646995
Packit Service 646995
	isns_config.ic_security = 0;
Packit Service 646995
	source = isns_source_create_iscsi(iname);
Packit Service 646995
	if (!source)
Packit Service 646995
		return ISCSI_ERR_NOMEM;
Packit Service 646995
Packit Service 646995
	clnt = isns_create_client(NULL, iname); 
Packit Service 646995
	if (!clnt) {
Packit Service 646995
		rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		goto free_src;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* do not retry forever */
Packit Service 646995
	isns_socket_set_disconnect_fatal(clnt->ic_socket);
Packit Service 646995
Packit Service 646995
	if (targetname)
Packit Service 646995
		isns_attr_list_append_string(&key_attrs, ISNS_TAG_ISCSI_NAME,
Packit Service 646995
					     targetname);
Packit Service 646995
	else
Packit Service 646995
		/* Query for all visible targets */
Packit Service 646995
		isns_attr_list_append_uint32(&key_attrs,
Packit Service 646995
					     ISNS_TAG_ISCSI_NODE_TYPE,
Packit Service 646995
					     ISNS_ISCSI_TARGET_MASK);
Packit Service 646995
Packit Service 646995
	qry = isns_create_query2(clnt, &key_attrs, source);
Packit Service 646995
	if (!qry) {
Packit Service 646995
		rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		goto free_clnt;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NAME);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_ISCSI_NODE_TYPE);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_IP_ADDRESS);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PORTAL_TCP_UDP_PORT);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PG_ISCSI_NAME);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_IP_ADDR);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PG_PORTAL_TCP_UDP_PORT);
Packit Service 646995
	isns_query_request_attr_tag(qry, ISNS_TAG_PG_TAG);
Packit Service 646995
Packit Service 646995
	status = isns_client_call(clnt, &qry);
Packit Service 646995
	switch (status) {
Packit Service 646995
	case ISNS_SUCCESS:
Packit Service 646995
		break;
Packit Service 646995
	case ISNS_SOURCE_UNKNOWN:
Packit Service 646995
		/* server requires that we are registered but we are not */
Packit Service 646995
		rc = ISCSI_ERR_ISNS_REG_FAILED;
Packit Service 646995
		goto free_query;
Packit Service 646995
	default:
Packit Service 646995
		log_error("iSNS discovery failed: %s", isns_strerror(status));
Packit Service 646995
		rc = ISCSI_ERR_ISNS_QUERY;
Packit Service 646995
		goto free_query;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	status = isns_query_response_get_objects(qry, &objects);
Packit Service 646995
	if (status) {
Packit Service 646995
		log_error("Unable to extract object list from query "
Packit Service 646995
			  "response: %s", isns_strerror(status));
Packit Service 646995
		rc = ISCSI_ERR;
Packit Service 646995
		goto free_query;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	for (unsigned int i = 0; i < objects.iol_count; ++i) {
Packit Service 646995
		isns_object_t *obj = objects.iol_data[i];
Packit Service 646995
		const char *pg_tgt = NULL;
Packit Service 646995
		struct in6_addr in_addr;
Packit Service 646995
		uint32_t pg_port = ISCSI_LISTEN_PORT;
Packit Service 646995
		uint32_t pg_tag = PORTAL_GROUP_TAG_UNKNOWN;
Packit Service 646995
		char pg_addr[INET6_ADDRSTRLEN + 1];
Packit Service 646995
		struct node_rec *rec;
Packit Service 646995
Packit Service 646995
		if (!isns_object_is_pg(obj))
Packit Service 646995
			continue;
Packit Service 646995
Packit Service 646995
		if (!isns_object_get_string(obj, ISNS_TAG_PG_ISCSI_NAME,
Packit Service 646995
					    &pg_tgt)) {
Packit Service 646995
			log_debug(1, "Missing target name");
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (!isns_object_get_ipaddr(obj, ISNS_TAG_PG_PORTAL_IP_ADDR,
Packit Service 646995
					    &in_addr)) {
Packit Service 646995
			log_debug(1, "Missing addr");
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
		if (IN6_IS_ADDR_V4MAPPED(&in_addr) ||
Packit Service 646995
		    IN6_IS_ADDR_V4COMPAT(&in_addr)) {
Packit Service 646995
			struct in_addr ipv4;
Packit Service 646995
Packit Service 646995
			ipv4.s_addr = in_addr.s6_addr32[3];
Packit Service 646995
			inet_ntop(AF_INET, &ipv4, pg_addr, sizeof(pg_addr));
Packit Service 646995
		} else
Packit Service 646995
			inet_ntop(AF_INET6, &in_addr, pg_addr, sizeof(pg_addr));
Packit Service 646995
Packit Service 646995
		if (!isns_object_get_uint32(obj,
Packit Service 646995
					    ISNS_TAG_PG_PORTAL_TCP_UDP_PORT,
Packit Service 646995
					    &pg_port)) {
Packit Service 646995
			log_debug(1, "Missing port");
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (!isns_object_get_uint32(obj, ISNS_TAG_PG_TAG, &pg_tag)) {
Packit Service 646995
			log_debug(1, "Missing tag");
Packit Service 646995
			continue;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		rec = calloc(1, sizeof(*rec));
Packit Service 646995
		if (!rec) {
Packit Service 646995
			rc = ISCSI_ERR_NOMEM;
Packit Service 646995
			goto destroy_list;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		idbm_node_setup_from_conf(rec);
Packit Service 646995
		if (drec) {
Packit Service 646995
			rec->disc_type = drec->type;
Packit Service 646995
			rec->disc_port = drec->port;
Packit Service 646995
			strcpy(rec->disc_address, drec->address);
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		strlcpy(rec->name, pg_tgt, TARGET_NAME_MAXLEN);
Packit Service 646995
		rec->tpgt = pg_tag;
Packit Service 646995
		rec->conn[0].port = pg_port;
Packit Service 646995
		strlcpy(rec->conn[0].address, pg_addr, NI_MAXHOST);
Packit Service 646995
		list_add_tail(&rec->list, rec_list);
Packit Service 646995
	}
Packit Service 646995
	rc = 0;
Packit Service 646995
Packit Service 646995
	isns_flush_events();
Packit Service 646995
destroy_list:
Packit Service 646995
	isns_object_list_destroy(&objects);
Packit Service 646995
free_query:
Packit Service 646995
	isns_simple_free(qry);
Packit Service 646995
free_clnt:
Packit Service 646995
	isns_client_destroy(clnt);
Packit Service 646995
free_src:
Packit Service 646995
	isns_source_release(source);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
/*
Packit Service 646995
 * discovery_isns_reg_node - register/deregister node
Packit Service 646995
 * @iname: initiator name
Packit Service 646995
 * @reg: bool indicating if we are supposed to register or deregister node.
Packit Service 646995
 *
Packit Service 646995
 * We do a very simple registration just so we can query.
Packit Service 646995
 */
Packit Service 646995
static int discovery_isns_reg_node(const char *iname, int op_reg)
Packit Service 646995
{
Packit Service 646995
	isns_simple_t *reg;
Packit Service 646995
	isns_client_t *clnt;
Packit Service 646995
	isns_source_t *source;
Packit Service 646995
	int rc = 0, status;
Packit Service 646995
Packit Service 646995
	isns_config.ic_security = 0;
Packit Service 646995
Packit Service 646995
	log_debug(1, "trying to %s %s with iSNS server.",
Packit Service 646995
		  op_reg ? "register" : "deregister", iname);
Packit Service 646995
Packit Service 646995
	source = isns_source_create_iscsi(iname);
Packit Service 646995
	if (!source)
Packit Service 646995
		return ISCSI_ERR_NOMEM;
Packit Service 646995
Packit Service 646995
	clnt = isns_create_client(NULL, iname); 
Packit Service 646995
	if (!clnt) {
Packit Service 646995
		rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		goto free_src;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	reg = isns_simple_create(op_reg ? ISNS_DEVICE_ATTRIBUTE_REGISTER :
Packit Service 646995
				 ISNS_DEVICE_DEREGISTER,
Packit Service 646995
				 source, NULL);
Packit Service 646995
	if (!reg) {
Packit Service 646995
		rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		goto free_clnt;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	isns_attr_list_append_string(&reg->is_operating_attrs,
Packit Service 646995
				     ISNS_TAG_ISCSI_NAME, iname);
Packit Service 646995
	if (op_reg)
Packit Service 646995
		isns_attr_list_append_uint32(&reg->is_operating_attrs,
Packit Service 646995
					     ISNS_TAG_ISCSI_NODE_TYPE,
Packit Service 646995
					     ISNS_ISCSI_INITIATOR_MASK);
Packit Service 646995
	status = isns_client_call(clnt, ®);
Packit Service 646995
	if (status != ISNS_SUCCESS) {
Packit Service 646995
		log_error("Could not %s %s with iSNS server: %s.",
Packit Service 646995
			  reg ? "register" : "deregister", iname,
Packit Service 646995
			  isns_strerror(status));
Packit Service 646995
		rc = ISCSI_ERR_ISNS_REG_FAILED;
Packit Service 646995
	} else
Packit Service 646995
		log_debug(1, "%s %s with iSNS server successful.",
Packit Service 646995
			  op_reg ? "register" : "deregister", iname);
Packit Service 646995
free_clnt:
Packit Service 646995
	isns_client_destroy(clnt);
Packit Service 646995
free_src:
Packit Service 646995
	isns_source_release(source);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int discovery_isns(void *data, struct iface_rec *iface,
Packit Service 646995
		   struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	struct discovery_rec *drec = data;
Packit Service 646995
	char *iname;
Packit Service 646995
	int rc, registered = 0;
Packit Service 646995
Packit Service 646995
	if (iface && strlen(iface->iname))
Packit Service 646995
		iname = iface->iname;
Packit Service 646995
	else {
Packit Service 646995
		rc = request_initiator_name(drec->iscsid_req_tmo);
Packit Service 646995
		if (rc) {
Packit Service 646995
			log_error("Cannot perform discovery. Initiatorname "
Packit Service 646995
				  "required.");
Packit Service 646995
			return rc;
Packit Service 646995
		} else if (initiator_name[0] == '\0') {
Packit Service 646995
			log_error("Cannot perform discovery. Invalid "
Packit Service 646995
				  "Initiatorname.");
Packit Service 646995
			return ISCSI_ERR_INVAL;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		iname = initiator_name;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	rc = discovery_isns_set_servername(drec->address, drec->port);
Packit Service 646995
	if (rc)
Packit Service 646995
		return rc;
Packit Service 646995
retry:
Packit Service 646995
	rc = discovery_isns_query(drec, iname, NULL, rec_list);
Packit Service 646995
	if (!registered && rc == ISCSI_ERR_ISNS_REG_FAILED) {
Packit Service 646995
		rc = discovery_isns_reg_node(iname, 1);
Packit Service 646995
		if (!rc) {
Packit Service 646995
			registered = 1;
Packit Service 646995
			goto retry;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (registered)
Packit Service 646995
		discovery_isns_reg_node(iname, 0);
Packit Service 646995
Packit Service 646995
	discovery_isns_free_servername();
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 2a7015
#endif
Packit Service 646995
Packit Service 646995
int discovery_fw(void *data,
Packit Service 646995
		 __attribute__((unused))struct iface_rec *iface,
Packit Service 646995
		 struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	struct discovery_rec *drec = data;
Packit Service 646995
	struct boot_context *bcontext;
Packit Service 646995
	struct list_head targets;
Packit Service 646995
	struct node_rec *rec;
Packit Service 646995
	int rc;
Packit Service 646995
Packit Service 646995
	INIT_LIST_HEAD(&targets;;
Packit Service 646995
	rc = fw_get_targets(&targets;;
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not get list of targets from firmware. "
Packit Service 646995
			  "(err %d)", rc);
Packit Service 646995
		return rc;
Packit Service 646995
	}
Packit Service 646995
	if (list_empty(&targets))
Packit Service 646995
		return 0;
Packit Service 646995
	/*
Packit Service 646995
	 * TODO: Do we want to match the iface MAC/netdev with what is in
Packit Service 646995
	 * the firmware or could the user want to bind based on what is
Packit Service 646995
	 * in passed in or in the default ifaces?
Packit Service 646995
	 */
Packit Service 646995
Packit Service 646995
	list_for_each_entry(bcontext, &targets, list) {
Packit Service 646995
		rec = idbm_create_rec_from_boot_context(bcontext);
Packit Service 646995
		if (!rec) {
Packit Service 646995
			log_error("Could not convert firmware info to "
Packit Service 646995
				  "node record.");
Packit Service 646995
			rc = ISCSI_ERR_NOMEM;
Packit Service 646995
			goto free_targets;
Packit Service 646995
		}
Packit Service 646995
		rec->disc_type = drec->type;
Packit Service 646995
Packit Service 646995
		list_add_tail(&rec->list, rec_list);
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
free_targets:
Packit Service 646995
	fw_free_targets(&targets;;
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int discovery_offload_sendtargets(int host_no, int do_login,
Packit Service 646995
				  discovery_rec_t *drec)
Packit Service 646995
{
Packit Service 646995
	struct sockaddr_storage ss;
Packit Service 646995
	char default_port[NI_MAXSERV];
Packit Service 646995
	iscsiadm_req_t req;
Packit Service 646995
	iscsiadm_rsp_t rsp;
Packit Service 646995
	int rc;
Packit Service 646995
Packit Service 646995
	log_debug(4, "offload st though host %d to %s", host_no,
Packit Service 646995
		  drec->address);
Packit Service 646995
Packit Service 646995
	memset(&req, 0, sizeof(req));
Packit Service 646995
	req.command = MGMT_IPC_SEND_TARGETS;
Packit Service 646995
	req.u.st.host_no = host_no;
Packit Service 646995
	req.u.st.do_login = do_login;
Packit Service 646995
Packit Service 646995
	/* resolve the DiscoveryAddress to an IP address */
Packit Service 646995
	sprintf(default_port, "%d", drec->port);
Packit Service 646995
	rc = resolve_address(drec->address, default_port, &ss);
Packit Service 646995
	if (rc)
Packit Service 646995
		return rc;
Packit Service 646995
Packit Service 646995
	req.u.st.ss = ss;
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * We only know how ask qla4xxx to do discovery and login
Packit Service 646995
	 * to what it finds. We are not able to get what it finds or
Packit Service 646995
	 * is able to log into so we just send the command and proceed.
Packit Service 646995
	 *
Packit Service 646995
	 * There is a way to just use the hw to send a sendtargets command
Packit Service 646995
	 * and get back the results. We should do this since it would
Packit Service 646995
	 * allows us to then process the results like software iscsi.
Packit Service 646995
	 */
Packit Service 646995
	rc = iscsid_exec_req(&req, &rsp, 1, drec->iscsid_req_tmo);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not offload sendtargets to %s.",
Packit Service 646995
			  drec->address);
Packit Service 646995
		iscsi_err_print_msg(rc);
Packit Service 646995
		return rc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return 0;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
iscsi_make_text_pdu(iscsi_session_t *session,
Packit Service 646995
		    struct iscsi_hdr *hdr,
Packit Service 646995
		    __attribute__((unused))char *data,
Packit Service 646995
		    __attribute__((unused))int max_data_length)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_text *text_pdu = (struct iscsi_text *)hdr;
Packit Service 646995
Packit Service 646995
	/* initialize the PDU header */
Packit Service 646995
	memset(text_pdu, 0, sizeof (*text_pdu));
Packit Service 646995
Packit Service 646995
	text_pdu->opcode = ISCSI_OP_TEXT;
Packit Service 646995
	text_pdu->itt = htonl(session->itt);
Packit Service 646995
	text_pdu->ttt = ISCSI_RESERVED_TAG;
Packit Service 646995
	text_pdu->cmdsn = htonl(session->cmdsn++);
Packit Service 646995
	text_pdu->exp_statsn = htonl(session->conn[0].exp_statsn);
Packit Service 646995
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
request_targets(iscsi_session_t *session)
Packit Service 646995
{
Packit Service 646995
	char data[64];
Packit Service 646995
	struct iscsi_text text;
Packit Service 646995
	struct iscsi_hdr *hdr = (struct iscsi_hdr *) &tex;;
Packit Service 646995
Packit Service 646995
	memset(&text, 0, sizeof (text));
Packit Service 646995
	memset(data, 0, sizeof (data));
Packit Service 646995
Packit Service 646995
	/* make a text PDU with SendTargets=All */
Packit Service 646995
	if (!iscsi_make_text_pdu(session, hdr, data, sizeof (data))) {
Packit Service 646995
		log_error("failed to make a SendTargets PDU");
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (!iscsi_add_text(hdr, data, sizeof (data), "SendTargets", "All")) {
Packit Service 646995
		log_error("failed to add SendTargets text key");
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	text.ttt = ISCSI_RESERVED_TAG;
Packit Service 646995
	text.flags = ISCSI_FLAG_CMD_FINAL;
Packit Service 646995
Packit Service 646995
	if (!iscsi_io_send_pdu(&session->conn[0], hdr, ISCSI_DIGEST_NONE, data,
Packit Service 646995
		    ISCSI_DIGEST_NONE, session->conn[0].active_timeout)) {
Packit Service 646995
		log_error("failed to send SendTargets PDU");
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
iterate_targets(iscsi_session_t *session, uint32_t ttt)
Packit Service 646995
{
Packit Service 646995
	char data[64];
Packit Service 646995
	struct iscsi_text text;
Packit Service 646995
	struct iscsi_hdr *pdu = (struct iscsi_hdr *) &tex;;
Packit Service 646995
Packit Service 646995
	memset(&text, 0, sizeof (text));
Packit Service 646995
	memset(data, 0, sizeof (data));
Packit Service 646995
Packit Service 646995
	/* make an empty text PDU */
Packit Service 646995
	if (!iscsi_make_text_pdu(session, pdu, data, sizeof (data))) {
Packit Service 646995
		log_error("failed to make an empty text PDU");
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	text.ttt = ttt;
Packit Service 646995
	text.flags = ISCSI_FLAG_CMD_FINAL;
Packit Service 646995
Packit Service 646995
	if (!iscsi_io_send_pdu(&session->conn[0], pdu, ISCSI_DIGEST_NONE, data,
Packit Service 646995
		    ISCSI_DIGEST_NONE, session->conn[0].active_timeout)) {
Packit Service 646995
		log_error("failed to send empty text PDU");
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int add_portal(struct list_head *rec_list, discovery_rec_t *drec,
Packit Service 646995
		      char *targetname, char *address, char *port, char *tag)
Packit Service 646995
{
Packit Service 646995
	struct sockaddr_storage ss;
Packit Service 646995
	struct node_rec *rec;
Packit Service 646995
Packit Service 646995
	if (resolve_address(address, port, &ss)) {
Packit Service 646995
		log_error("cannot resolve %s", address);
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	rec = calloc(1, sizeof(*rec));
Packit Service 646995
	if (!rec)
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
	idbm_node_setup_from_conf(rec);
Packit Service 646995
	rec->disc_type = drec->type;
Packit Service 646995
	rec->disc_port = drec->port;
Packit Service 646995
	strcpy(rec->disc_address, drec->address);
Packit Service 646995
Packit Service 646995
	strlcpy(rec->name, targetname, TARGET_NAME_MAXLEN);
Packit Service 646995
	if (tag && *tag)
Packit Service 646995
		rec->tpgt = atoi(tag);
Packit Service 646995
	else
Packit Service 646995
		rec->tpgt = PORTAL_GROUP_TAG_UNKNOWN;
Packit Service 646995
	if (port && *port)
Packit Service 646995
		rec->conn[0].port = atoi(port);
Packit Service 646995
	else
Packit Service 646995
		rec->conn[0].port = ISCSI_LISTEN_PORT;
Packit Service 646995
	strlcpy(rec->conn[0].address, address, NI_MAXHOST);
Packit Service 646995
Packit Service 646995
	list_add_tail(&rec->list, rec_list);
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
add_target_record(char *name, char *end, discovery_rec_t *drec,
Packit Service 646995
		  struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	char *text = NULL;
Packit Service 646995
	char *nul = name;
Packit Service 646995
	size_t length;
Packit Service 646995
Packit Service 646995
	/* address = IPv4
Packit Service 646995
	 * address = [IPv6]
Packit Service 646995
	 * address = DNSname
Packit Service 646995
	 * address = IPv4:port
Packit Service 646995
	 * address = [IPv6]:port
Packit Service 646995
	 * address = DNSname:port
Packit Service 646995
	 * address = IPv4,tag
Packit Service 646995
	 * address = [IPv6],tag
Packit Service 646995
	 * address = DNSname,tag
Packit Service 646995
	 * address = IPv4:port,tag
Packit Service 646995
	 * address = [IPv6]:port,tag
Packit Service 646995
	 * address = DNSname:port,tag
Packit Service 646995
	 */
Packit Service 646995
Packit Service 646995
	log_debug(7, "adding target record %p, end %p", name, end);
Packit Service 646995
Packit Service 646995
	/* find the end of the name */
Packit Service 646995
	while ((nul < end) && (*nul != '\0'))
Packit Service 646995
		nul++;
Packit Service 646995
Packit Service 646995
	length = nul - name;
Packit Service 646995
	if (length > TARGET_NAME_MAXLEN) {
Packit Service 646995
		log_error("TargetName %s too long, ignoring", name);
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
	text = name + length;
Packit Service 646995
Packit Service 646995
	/* skip NULs after the name */
Packit Service 646995
	while ((text < end) && (*text == '\0'))
Packit Service 646995
		text++;
Packit Service 646995
Packit Service 646995
	/* if no address is provided, use the default */
Packit Service 646995
	if (text >= end) {
Packit Service 646995
		if (drec->address == NULL) {
Packit Service 646995
			log_error("no default address known for target %s",
Packit Service 646995
				  name);
Packit Service 646995
			return 0;
Packit Service 646995
		} else {
Packit Service 646995
			char default_port[NI_MAXSERV];
Packit Service 646995
Packit Service 646995
			sprintf(default_port, "%d", drec->port);
Packit Service 646995
			if (!add_portal(rec_list, drec, name, drec->address,
Packit Service 646995
				        default_port, NULL)) {
Packit Service 646995
				log_error("failed to add default portal, "
Packit Service 646995
					  "ignoring target %s", name);
Packit Service 646995
				return 0;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
		/* finished adding the default */
Packit Service 646995
		return 1;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* process TargetAddresses */
Packit Service 646995
	while (text < end) {
Packit Service 646995
		char *next = text + strlen(text) + 1;
Packit Service 646995
Packit Service 646995
		log_debug(7, "text %p, next %p, end %p, %s", text, next, end,
Packit Service 646995
			 text);
Packit Service 646995
Packit Service 646995
		if (strncmp(text, "TargetAddress=", 14) == 0) {
Packit Service 646995
			char *port = NULL;
Packit Service 646995
			char *tag = NULL;
Packit Service 646995
			char *address = text + 14;
Packit Service 646995
			char *temp;
Packit Service 646995
Packit Service 646995
			if ((tag = strrchr(text, ','))) {
Packit Service 646995
				*tag = '\0';
Packit Service 646995
				tag++;
Packit Service 646995
			}
Packit Service 646995
			if ((port = strrchr(text, ':'))) {
Packit Service 646995
				*port = '\0';
Packit Service 646995
				port++;
Packit Service 646995
			}
Packit Service 646995
Packit Service 646995
			if (*address == '[') {
Packit Service 646995
				address++;
Packit Service 646995
				if ((temp = strrchr(text, ']')))
Packit Service 646995
					*temp = '\0';
Packit Service 646995
			}
Packit Service 646995
Packit Service 646995
			if (!add_portal(rec_list, drec, name, address, port,
Packit Service 646995
					tag)) {
Packit Service 646995
				log_error("failed to add default portal, "
Packit Service 646995
					 "ignoring target %s", name);
Packit Service 646995
				return 0;
Packit Service 646995
			}
Packit Service 646995
		} else
Packit Service 646995
			log_error("unexpected SendTargets data: %s",
Packit Service 646995
			       text);
Packit Service 646995
		text = next;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
process_sendtargets_response(struct str_buffer *sendtargets,
Packit Service 646995
			     int final, discovery_rec_t *drec,
Packit Service 646995
			     struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	char *start = str_buffer_data(sendtargets);
Packit Service 646995
	char *text = start;
Packit Service 646995
	char *end = text + str_data_length(sendtargets);
Packit Service 646995
	char *nul = end - 1;
Packit Service 646995
	char *record = NULL;
Packit Service 646995
	int num_targets = 0;
Packit Service 646995
Packit Service 646995
	if (start == end) {
Packit Service 646995
		/* no SendTargets data */
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* scan backwards to find the last NUL in the data, to ensure we
Packit Service 646995
	 * don't walk off the end.  Since key=value pairs can span PDU
Packit Service 646995
	 * boundaries, we're not guaranteed that the end of the data has a
Packit Service 646995
	 * NUL.
Packit Service 646995
	 */
Packit Service 646995
	while ((nul > start) && *nul)
Packit Service 646995
		nul--;
Packit Service 646995
Packit Service 646995
	if (nul == start) {
Packit Service 646995
		/* couldn't find anything we can process now,
Packit Service 646995
		 * it's one big partial string
Packit Service 646995
		 */
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* find the boundaries between target records (TargetName or final PDU)
Packit Service 646995
	 */
Packit Service 646995
	for (;;) {
Packit Service 646995
		/* skip NULs */
Packit Service 646995
		while ((text < nul) && (*text == '\0'))
Packit Service 646995
			text++;
Packit Service 646995
Packit Service 646995
		if (text == nul)
Packit Service 646995
			break;
Packit Service 646995
Packit Service 646995
		log_debug(7,
Packit Service 646995
			 "processing sendtargets record %p, text %p, line %s",
Packit Service 646995
			 record, text, text);
Packit Service 646995
Packit Service 646995
		/* look for the start of a new target record */
Packit Service 646995
		if (strncmp(text, "TargetName=", 11) == 0) {
Packit Service 646995
			if (record) {
Packit Service 646995
				/* send the last record, which we just found
Packit Service 646995
				 * the end of. don't bother passing the
Packit Service 646995
				 * "TargetName=" prefix.
Packit Service 646995
				 */
Packit Service 646995
				if (!add_target_record(record + 11, text,
Packit Service 646995
							drec, rec_list)) {
Packit Service 646995
					log_error(
Packit Service 646995
					       "failed to add target record");
Packit Service 646995
					str_truncate_buffer(sendtargets, 0);
Packit Service 646995
					goto done;
Packit Service 646995
				}
Packit Service 646995
				num_targets++;
Packit Service 646995
			}
Packit Service 646995
			record = text;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		/* everything up til the next NUL must be part of the
Packit Service 646995
		 * current target record
Packit Service 646995
		 */
Packit Service 646995
		while ((text < nul) && (*text != '\0'))
Packit Service 646995
			text++;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (record) {
Packit Service 646995
		if (final) {
Packit Service 646995
			/* if this is the last PDU of the text sequence,
Packit Service 646995
			 * it also ends a target record
Packit Service 646995
			 */
Packit Service 646995
			log_debug(7,
Packit Service 646995
				 "processing final sendtargets record %p, "
Packit Service 646995
				 "line %s",
Packit Service 646995
				 record, record);
Packit Service 646995
			if (add_target_record (record + 11, text,
Packit Service 646995
					       drec, rec_list)) {
Packit Service 646995
				num_targets++;
Packit Service 646995
				record = NULL;
Packit Service 646995
				str_truncate_buffer(sendtargets, 0);
Packit Service 646995
			} else {
Packit Service 646995
				log_error("failed to add target record");
Packit Service 646995
				str_truncate_buffer(sendtargets, 0);
Packit Service 646995
				goto done;
Packit Service 646995
			}
Packit Service 646995
		} else {
Packit Service 646995
			/* remove the parts of the sendtargets buffer we've
Packit Service 646995
			 * processed, and move the parts we haven't to the
Packit Service 646995
			 * beginning of the buffer.
Packit Service 646995
			 */
Packit Service 646995
			log_debug(7,
Packit Service 646995
				 "processed %d bytes of sendtargets data, "
Packit Service 646995
				 "%d remaining",
Packit Service 646995
				 (int)(record - str_buffer_data(sendtargets)),
Packit Service 646995
				 (int)(str_buffer_data(sendtargets) +
Packit Service 646995
				 str_data_length(sendtargets) - record));
Packit Service 646995
			str_remove_initial(sendtargets,
Packit Service 646995
					   record - str_buffer_data(sendtargets));
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
      done:
Packit Service 646995
Packit Service 646995
	return 1;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static void iscsi_free_session(struct iscsi_session *session)
Packit Service 646995
{
Packit Service 646995
	list_del_init(&session->list);
Packit Service 646995
	free(session);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static iscsi_session_t *
Packit Service 646995
iscsi_alloc_session(struct iscsi_sendtargets_config *config,
Packit Service 646995
		    struct iface_rec *iface, int *rc, int tmo)
Packit Service 646995
{
Packit Service 646995
	iscsi_session_t *session;
Packit Service 646995
Packit Service 646995
	*rc = 0;
Packit Service 646995
Packit Service 646995
	session = calloc(1, sizeof (*session));
Packit Service 646995
	if (session == NULL) {
Packit Service 646995
		*rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		return NULL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	session->t = iscsi_sysfs_get_transport_by_name(iface->transport_name);
Packit Service 646995
	if (!session->t) {
Packit Service 646995
		log_error("iSCSI driver %s is not loaded. Load the module "
Packit Service 646995
			  "then retry the command.", iface->transport_name);
Packit Service 646995
		*rc = ISCSI_ERR_TRANS_NOT_FOUND;
Packit Service 646995
		goto fail;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	INIT_LIST_HEAD(&session->list);
Packit Service 646995
	/* initialize the session's leading connection */
Packit Service 646995
	session->conn[0].id = 0;
Packit Service 646995
	session->conn[0].socket_fd = -1;
Packit Service 646995
	session->conn[0].session = session;
Packit Service 646995
	session->conn[0].login_timeout = config->conn_timeo.login_timeout;
Packit Service 646995
	session->conn[0].auth_timeout = config->conn_timeo.auth_timeout;
Packit Service 646995
	session->conn[0].active_timeout = config->conn_timeo.active_timeout;
Packit Service 646995
	session->conn[0].noop_out_timeout = 0;
Packit Service 646995
	session->conn[0].noop_out_interval = 0;
Packit Service 646995
	session->reopen_cnt = config->reopen_max + 1;
Packit Service 646995
	iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
Packit Service 646995
				      &config->conn_conf);
Packit Service 646995
Packit Service 646995
	/* OUI and uniqifying number */
Packit Service 646995
	session->isid[0] = DRIVER_ISID_0;
Packit Service 646995
	session->isid[1] = DRIVER_ISID_1;
Packit Service 646995
	session->isid[2] = DRIVER_ISID_2;
Packit Service 646995
	session->isid[3] = 0;
Packit Service 646995
	session->isid[4] = 0;
Packit Service 646995
	session->isid[5] = 0;
Packit Service 646995
Packit Service 646995
	if (strlen(iface->iname)) {
Packit Service 646995
		strcpy(initiator_name, iface->iname);
Packit Service 646995
		/* MNC TODO add iface alias */
Packit Service 646995
	} else {
Packit Service 646995
		*rc = request_initiator_name(tmo);
Packit Service 646995
		if (*rc) {
Packit Service 646995
			log_error("Cannot perform discovery. Initiatorname "
Packit Service 646995
				  "required.");
Packit Service 646995
			goto fail;
Packit Service 646995
		} else if (initiator_name[0] == '\0') {
Packit Service 646995
			log_error("Cannot perform discovery. Invalid "
Packit Service 646995
				  "Initiatorname.");
Packit Service 646995
			*rc = ISCSI_ERR_INVAL;
Packit Service 646995
			goto fail;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	iface_copy(&session->nrec.iface, iface);
Packit Service 646995
	session->initiator_name = initiator_name;
Packit Service 646995
	session->initiator_alias = initiator_alias;
Packit Service 646995
	session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
Packit Service 646995
	session->type = ISCSI_SESSION_TYPE_DISCOVERY;
Packit Service 646995
	session->id = INVALID_SESSION_ID;
Packit Service 646995
Packit Service 646995
	/* setup authentication variables for the session*/
Packit Service 646995
	*rc = iscsi_setup_authentication(session, &config->auth);
Packit Service 646995
	if (*rc)
Packit Service 646995
		goto fail;
Packit Service 646995
Packit Service 646995
	list_add_tail(&session->list, &session->t->sessions);
Packit Service 646995
	return session;
Packit Service 646995
Packit Service 646995
fail:
Packit Service 646995
	free(session);
Packit Service 646995
	return NULL;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int
Packit Service 646995
process_recvd_pdu(struct iscsi_hdr *pdu,
Packit Service 646995
		  discovery_rec_t *drec,
Packit Service 646995
		  struct list_head *rec_list,
Packit Service 646995
		  iscsi_session_t *session,
Packit Service 646995
		  struct str_buffer *sendtargets,
Packit Service 646995
		  int *active,
Packit Service 646995
		  int *valid_text,
Packit Service 646995
		  char *data)
Packit Service 646995
{
Packit Service 646995
	int rc=0;
Packit Service 646995
Packit Service 646995
	switch (pdu->opcode) {
Packit Service 646995
		case ISCSI_OP_TEXT_RSP:{
Packit Service 646995
			struct iscsi_text_rsp *text_response =
Packit Service 646995
				(struct iscsi_text_rsp *) pdu;
Packit Service 646995
			int dlength = ntoh24(pdu->dlength);
Packit Service 646995
			int final =
Packit Service 646995
				(text_response->flags & ISCSI_FLAG_CMD_FINAL) ||
Packit Service 646995
				(text_response-> ttt == ISCSI_RESERVED_TAG);
Packit Service 646995
			size_t curr_data_length;
Packit Service 646995
Packit Service 646995
			log_debug(4, "discovery session to %s:%d received text"
Packit Service 646995
				 " response, %d data bytes, ttt 0x%x, "
Packit Service 646995
				 "final 0x%x",
Packit Service 646995
				 drec->address,
Packit Service 646995
				 drec->port,
Packit Service 646995
				 dlength,
Packit Service 646995
				 ntohl(text_response->ttt),
Packit Service 646995
				 text_response->flags & ISCSI_FLAG_CMD_FINAL);
Packit Service 646995
Packit Service 646995
			/* mark how much more data in the sendtargets
Packit Service 646995
			 * buffer is now valid
Packit Service 646995
			 */
Packit Service 646995
			curr_data_length = str_data_length(sendtargets);
Packit Service 646995
			if (str_enlarge_data(sendtargets, dlength)) {
Packit Service 646995
				log_error("Could not allocate memory to "
Packit Service 646995
					  "process SendTargets response.");
Packit Service 646995
				rc = 0;
Packit Service 646995
				goto done;
Packit Service 646995
			}
Packit Service 646995
Packit Service 646995
			memcpy(str_buffer_data(sendtargets) + curr_data_length,
Packit Service 646995
			       data, dlength);
Packit Service 646995
Packit Service 646995
			*valid_text = 1;
Packit Service 646995
			/* process as much as we can right now */
Packit Service 646995
			process_sendtargets_response(sendtargets,
Packit Service 646995
						     final,
Packit Service 646995
						     drec,
Packit Service 646995
						     rec_list);
Packit Service 646995
Packit Service 646995
			if (final) {
Packit Service 646995
				/* SendTargets exchange is now complete
Packit Service 646995
				 */
Packit Service 646995
				*active = 0;
Packit Service 646995
				/* from now on, after any reconnect,
Packit Service 646995
				 * assume LUNs may have changed
Packit Service 646995
				 */
Packit Service 646995
			} else {
Packit Service 646995
				/* ask for more targets */
Packit Service 646995
				if (!iterate_targets(session,
Packit Service 646995
						     text_response->ttt)) {
Packit Service 646995
					rc = DISCOVERY_NEED_RECONNECT;
Packit Service 646995
					goto done;
Packit Service 646995
				}
Packit Service 646995
			}
Packit Service 646995
			break;
Packit Service 646995
		}
Packit Service 646995
		default:
Packit Service 646995
			log_warning(
Packit Service 646995
			       "discovery session to %s:%d received "
Packit Service 646995
			       "unexpected opcode 0x%x",
Packit Service 646995
			       drec->address, drec->port, pdu->opcode);
Packit Service 646995
			rc = DISCOVERY_NEED_RECONNECT;
Packit Service 646995
			goto done;
Packit Service 646995
	}
Packit Service 646995
 done:
Packit Service 646995
	return(rc);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#if 0 /* Unused */
Packit Service 646995
/*
Packit Service 646995
 * Make a best effort to logout the session.
Packit Service 646995
 */
Packit Service 646995
static void iscsi_logout(iscsi_session_t * session)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_logout logout_req;
Packit Service 646995
	struct iscsi_logout_rsp logout_resp;
Packit Service 646995
	int rc;
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Build logout request header
Packit Service 646995
	 */
Packit Service 646995
	memset(&logout_req, 0, sizeof (logout_req));
Packit Service 646995
	logout_req.opcode = ISCSI_OP_LOGOUT | ISCSI_OP_IMMEDIATE;
Packit Service 646995
	logout_req.flags = ISCSI_FLAG_CMD_FINAL |
Packit Service 646995
		(ISCSI_LOGOUT_REASON_CLOSE_SESSION &
Packit Service 646995
				ISCSI_FLAG_LOGOUT_REASON_MASK);
Packit Service 646995
	logout_req.itt = htonl(session->itt);
Packit Service 646995
	if (++session->itt == ISCSI_RESERVED_TAG)
Packit Service 646995
		session->itt = 1;
Packit Service 646995
	logout_req.cmdsn = htonl(session->cmdsn);
Packit Service 646995
	logout_req.exp_statsn = htonl(++session->conn[0].exp_statsn);
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Send the logout request
Packit Service 646995
	 */
Packit Service 646995
	rc = iscsi_io_send_pdu(&session->conn[0],(struct iscsi_hdr *)&logout_req,
Packit Service 646995
			    ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 3);
Packit Service 646995
	if (!rc) {
Packit Service 646995
		log_error(
Packit Service 646995
		       "iscsid: iscsi_logout - failed to send logout PDU.");
Packit Service 646995
		return;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Read the logout response
Packit Service 646995
	 */
Packit Service 646995
	memset(&logout_resp, 0, sizeof(logout_resp));
Packit Service 646995
	rc = iscsi_io_recv_pdu(&session->conn[0],
Packit Service 646995
		(struct iscsi_hdr *)&logout_resp, ISCSI_DIGEST_NONE, NULL,
Packit Service 646995
		0, ISCSI_DIGEST_NONE, 1);
Packit Service 646995
	if (rc < 0) {
Packit Service 646995
		log_error("iscsid: logout - failed to receive logout resp");
Packit Service 646995
		return;
Packit Service 646995
	}
Packit Service 646995
	if (logout_resp.response != ISCSI_LOGOUT_SUCCESS) {
Packit Service 646995
		log_error("iscsid: logout failed - response = 0x%x",
Packit Service 646995
		       logout_resp.response);
Packit Service 646995
	}
Packit Service 646995
}
Packit Service 646995
#endif /* Unused */
Packit Service 646995
Packit Service 646995
static void iscsi_destroy_session(struct iscsi_session *session)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_transport *t = session->t;
Packit Service 646995
	struct iscsi_conn *conn = &session->conn[0];
Packit Service 646995
	int rc;
Packit Service 646995
Packit Service 646995
	if (session->id == INVALID_SESSION_ID)
Packit Service 646995
		return;
Packit Service 646995
Packit Service 646995
	if (!(t->caps & CAP_TEXT_NEGO)) {
Packit Service 646995
		iscsi_io_disconnect(&session->conn[0]);
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s ep disconnect", __FUNCTION__);
Packit Service 646995
	t->template->ep_disconnect(conn);
Packit Service 646995
Packit Service 646995
	log_debug(2, "stop conn");
Packit Service 646995
	rc = ipc->stop_conn(session->t->handle, session->id,
Packit Service 646995
			   conn->id, STOP_CONN_TERM);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not stop conn %d:%d cleanly (err %d)",
Packit Service 646995
			  session->id, conn->id, rc);
Packit Service 646995
		goto done;
Packit Service 646995
        }
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s destroy conn", __FUNCTION__);
Packit Service 646995
        rc = ipc->destroy_conn(session->t->handle, session->id, conn->id);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not safely destroy conn %d:%d (err %d)",
Packit Service 646995
			  session->id, conn->id, rc);
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s destroy session", __FUNCTION__);
Packit Service 646995
	rc = ipc->destroy_session(session->t->handle, session->id);
Packit Service 646995
	if (rc)
Packit Service 646995
		log_error("Could not safely destroy session %d (err %d)",
Packit Service 646995
			  session->id, rc);
Packit Service 646995
done:
Packit Service 646995
	if (session->target_alias) {
Packit Service 646995
	    free(session->target_alias);
Packit Service 646995
	    session->target_alias = NULL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (conn->socket_fd >= 0) {
Packit Service 646995
		ipc->ctldev_close();
Packit Service 646995
		conn->socket_fd = -1;
Packit Service 646995
	}
Packit Service 646995
	session->id = INVALID_SESSION_ID;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int iscsi_create_leading_conn(struct iscsi_session *session)
Packit Service 646995
{
Packit Service 646995
	struct iface_rec *iface = &session->nrec.iface;
Packit Service 646995
	struct iscsi_transport *t = session->t;
Packit Service 646995
	struct iscsi_conn *conn = &session->conn[0];
Packit Service 646995
	uint32_t host_no;
Packit Service 646995
	int rc, sleep_count = 0;
Packit Service 646995
Packit Service 646995
	if (!(t->caps & CAP_TEXT_NEGO)) {
Packit Service 646995
		/*
Packit Service 646995
		 * If the LLD does not support TEXT PDUs then we do
Packit Service 646995
		 * discovery in userspace.
Packit Service 646995
		 */
Packit Service 646995
		session->use_ipc = 0;
Packit Service 646995
Packit Service 646995
		if (!iscsi_io_connect(conn))
Packit Service 646995
			return ISCSI_ERR_TRANS;
Packit Service 646995
Packit Service 646995
		session->id = 1;
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
	session->use_ipc = 1;
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * for software this is the tcp socket fd set in iscsi_io_connect
Packit Service 646995
	 * and for offload this is the iscsi netlink socket fd
Packit Service 646995
	 */
Packit Service 646995
	conn->socket_fd = ipc->ctldev_open();
Packit Service 646995
	if (conn->socket_fd < 0) {
Packit Service 646995
		log_error("Could not open netlink interface (err %d)",
Packit Service 646995
			  errno);
Packit Service 646995
		return ISCSI_ERR_INTERNAL;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	host_no = iscsi_sysfs_get_host_no_from_hwinfo(iface, &rc);
Packit Service 646995
	if (!rc) {
Packit Service 646995
		/*
Packit Service 646995
		 * if the netdev or mac was set, then we are going to want
Packit Service 646995
		 * to want to bind the all the conns/eps to a specific host
Packit Service 646995
		 * if offload is used.
Packit Service 646995
		 */
Packit Service 646995
		session->conn[0].bind_ep = 1;
Packit Service 646995
		session->hostno = host_no;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	rc = iscsi_host_set_net_params(iface, session);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not set host net params (err %d)",
Packit Service 646995
			  rc);
Packit Service 646995
		if (rc != ISCSI_ERR_AGAIN)
Packit Service 646995
			rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto close_ipc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* create interconnect endpoint */
Packit Service 646995
	log_debug(2, "%s discovery ep connect", __FUNCTION__);
Packit Service 646995
	rc = t->template->ep_connect(conn, 1);
Packit Service 646995
	if (rc < 0) {
Packit Service 646995
		rc = ISCSI_ERR_TRANS;
Packit Service 646995
		goto close_ipc;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	do {
Packit Service 646995
		rc = t->template->ep_poll(conn, 1);
Packit Service 646995
		if (rc < 0) {
Packit Service 646995
			rc = ISCSI_ERR_TRANS;
Packit Service 646995
			goto disconnect;
Packit Service 646995
		} else if (rc == 0) {
Packit Service 646995
			if (sleep_count == conn->login_timeout) {
Packit Service 646995
				rc = ISCSI_ERR_TRANS_TIMEOUT;
Packit Service 646995
				goto disconnect;
Packit Service 646995
			}
Packit Service 646995
			sleep_count++;
Packit Service 646995
			sleep(1);
Packit Service 646995
		} else
Packit Service 646995
			break;
Packit Service 646995
	} while (1);
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s discovery create session", __FUNCTION__);
Packit Service 646995
	/* create kernel structs */
Packit Service 646995
        rc = ipc->create_session(session->t->handle,
Packit Service 646995
				 conn->transport_ep_handle, 1, 32, 1,
Packit Service 646995
				 &session->id, &host_no);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not create kernel session (err %d).", rc);
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto disconnect;
Packit Service 646995
	}
Packit Service 646995
	log_debug(2, "%s discovery created session %u", __FUNCTION__,
Packit Service 646995
		  session->id);
Packit Service 646995
	session->isid[3] = (session->id >> 16) & 0xff;
Packit Service 646995
	session->isid[4] = (session->id >>  8) & 0xff;
Packit Service 646995
	session->isid[5] = session->id & 0xff;
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s discovery create conn", __FUNCTION__);
Packit Service 646995
	rc = ipc->create_conn(t->handle, session->id, conn->id, &conn->id);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not create connection (err %d)", rc);
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto disconnect;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s discovery bind conn", __FUNCTION__);
Packit Service 646995
	if (ipc->bind_conn(t->handle, session->id, conn->id,
Packit Service 646995
			   conn->transport_ep_handle, (conn->id == 0), &rc) ||
Packit Service 646995
	    rc) {
Packit Service 646995
		log_error("Could not bind conn %d:%d to session %d, "
Packit Service 646995
			  "(err %d)", session->id, conn->id,
Packit Service 646995
			  session->id, rc);
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto disconnect;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* all set */
Packit Service 646995
	return 0;
Packit Service 646995
Packit Service 646995
disconnect:
Packit Service 646995
	t->template->ep_disconnect(conn);
Packit Service 646995
Packit Service 646995
	if (session->id != INVALID_SESSION_ID &&
Packit Service 646995
	    iscsi_sysfs_session_has_leadconn(session->id)) {
Packit Service 646995
		if (ipc->destroy_conn(session->t->handle, session->id,
Packit Service 646995
				       conn->id))
Packit Service 646995
			log_error("Could not safely destroy connection %d:%d",
Packit Service 646995
				  session->id, conn->id);
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (session->id != INVALID_SESSION_ID) {
Packit Service 646995
		if (ipc->destroy_session(session->t->handle, session->id))
Packit Service 646995
			log_error("Could not safely destroy session %d",
Packit Service 646995
				  session->id);
Packit Service 646995
		session->id = INVALID_SESSION_ID;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
close_ipc:
Packit Service 646995
	if (conn->socket_fd >= 0) {
Packit Service 646995
		ipc->ctldev_close();
Packit Service 646995
		conn->socket_fd = -1;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_error("Connection to discovery portal %s failed: %s",
Packit Service 646995
		  conn->host, iscsi_err_to_str(rc));
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static struct iscsi_ev_context *
Packit Service 646995
iscsi_ev_context_get(__attribute__((unused))struct iscsi_conn *conn,
Packit Service 646995
		     int ev_size)
Packit Service 646995
{
Packit Service 646995
	log_debug(2, "%s: ev_size %d", __FUNCTION__, ev_size);
Packit Service 646995
Packit Service 646995
	ipc_ev_context.data = calloc(1, ev_size);
Packit Service 646995
	if (!ipc_ev_context.data)
Packit Service 646995
		return NULL;
Packit Service 646995
Packit Service 646995
	return &ipc_ev_context;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static void iscsi_ev_context_put(struct iscsi_ev_context *ev_context)
Packit Service 646995
{
Packit Service 646995
	if (ev_context->data)
Packit Service 646995
		free(ev_context->data);
Packit Service 646995
	ev_context->data = NULL;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int iscsi_sched_ev_context(struct iscsi_ev_context *ev_context,
Packit Service 646995
				  struct iscsi_conn *conn,
Packit Service 646995
				  __attribute__((unused))unsigned long tmo,
Packit Service 646995
				  int event)
Packit Service 646995
{
Packit Service 646995
	if (event == EV_CONN_RECV_PDU || event == EV_CONN_LOGIN) {
Packit Service 646995
		conn->recv_context = ev_context;
Packit Service 646995
		return 0;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	return -EIO;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static struct iscsi_ipc_ev_clbk ipc_clbk = {
Packit Service 646995
        .get_ev_context         = iscsi_ev_context_get,
Packit Service 646995
        .put_ev_context         = iscsi_ev_context_put,
Packit Service 646995
        .sched_ev_context       = iscsi_sched_ev_context,
Packit Service 646995
};
Packit Service 646995
Packit Service 646995
static int iscsi_wait_for_login(struct iscsi_conn *conn)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_session *session = conn->session;
Packit Service 646995
	struct iscsi_transport *t = session->t;
Packit Service 646995
	struct pollfd pfd;
Packit Service 646995
	struct timeval connection_timer;
Packit Service 646995
	int timeout, rc;
Packit Service 646995
	uint32_t conn_state;
Packit Service 646995
	int status = 0;
Packit Service 646995
Packit Service 646995
	if (!(t->caps & CAP_LOGIN_OFFLOAD))
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
	iscsi_timer_set(&connection_timer, conn->active_timeout);
Packit Service 646995
Packit Service 646995
	/* prepare to poll */
Packit Service 646995
	memset(&pfd, 0, sizeof(pfd));
Packit Service 646995
	pfd.fd = conn->socket_fd;
Packit Service 646995
	pfd.events = POLLIN | POLLPRI;
Packit Service 646995
Packit Service 646995
	timeout = iscsi_timer_msecs_until(&connection_timer);
Packit Service 646995
Packit Service 646995
login_repoll:
Packit Service 646995
	log_debug(4, "discovery login process polling fd %d, "
Packit Service 646995
		 "timeout in %f seconds", pfd.fd, timeout / 1000.0);
Packit Service 646995
Packit Service 646995
	pfd.revents = 0;
Packit Service 646995
	rc = poll(&pfd, 1, timeout);
Packit Service 646995
Packit Service 646995
	log_debug(7, "discovery login process returned from poll, rc %d", rc);
Packit Service 646995
Packit Service 646995
	if (iscsi_timer_expired(&connection_timer)) {
Packit Service 646995
		log_warning("Discovery login session timed out.");
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (rc > 0) {
Packit Service 646995
		if (pfd.revents & (POLLIN | POLLPRI)) {
Packit Service 646995
			timeout = iscsi_timer_msecs_until(&connection_timer);
Packit Service 646995
			status = ipc->recv_conn_state(conn, &conn_state);
Packit Service 646995
			if (status == -EAGAIN)
Packit Service 646995
				goto login_repoll;
Packit Service 646995
			else if (status < 0) {
Packit Service 646995
				rc = ISCSI_ERR_TRANS;
Packit Service 646995
				goto done;
Packit Service 646995
			}
Packit Service 646995
Packit Service 646995
			if (conn_state != ISCSI_CONN_STATE_LOGGED_IN)
Packit Service 646995
				rc = ISCSI_ERR_TRANS;
Packit Service 646995
			else
Packit Service 646995
				rc = 0;
Packit Service 646995
			goto done;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLHUP) {
Packit Service 646995
			log_warning("discovery session"
Packit Service 646995
				    "terminating after hangup");
Packit Service 646995
			 rc = ISCSI_ERR_TRANS;
Packit Service 646995
			 goto done;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLNVAL) {
Packit Service 646995
			log_warning("discovery POLLNVAL");
Packit Service 646995
			rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
			goto done;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLERR) {
Packit Service 646995
			log_warning("discovery POLLERR");
Packit Service 646995
			rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
			goto done;
Packit Service 646995
		}
Packit Service 646995
	} else if (rc < 0) {
Packit Service 646995
		log_error("Login poll error");
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto done;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
done:
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
static int iscsi_create_session(struct iscsi_session *session,
Packit Service 646995
				struct iscsi_sendtargets_config *config,
Packit Service 646995
				char *data, unsigned int data_len)
Packit Service 646995
{
Packit Service 646995
	struct iscsi_conn *conn = &session->conn[0];
Packit Service 646995
	int login_status, rc = 0, login_delay = 0;
Packit Service 646995
	uint8_t status_class = 0, status_detail = 0;
Packit Service 646995
	unsigned int login_failures = 0;
Packit Service 646995
	char serv[NI_MAXSERV];
Packit Service 646995
	struct iscsi_transport *t = session->t;
Packit Service 646995
Packit Service 646995
set_address:
Packit Service 646995
	/*
Packit Service 646995
	 * copy the saved address to the session,
Packit Service 646995
	 * undoing any temporary redirect
Packit Service 646995
	 */
Packit Service 646995
	conn->saddr = conn->failback_saddr;
Packit Service 646995
Packit Service 646995
reconnect:
Packit Service 646995
	/* fix decrement and test */
Packit Service 646995
	if (--session->reopen_cnt < 0) {
Packit Service 646995
		log_error("connection login retries (reopen_max) %d exceeded",
Packit Service 646995
			  config->reopen_max);
Packit Service 646995
		rc = ISCSI_ERR_PDU_TIMEOUT;
Packit Service 646995
		goto login_failed;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
redirect_reconnect:
Packit Service 646995
	session->cmdsn = 1;
Packit Service 646995
	session->itt = 1;
Packit Service 646995
	session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN;
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * On reconnect, just destroy the kernel structs and start over.
Packit Service 646995
	 */
Packit Service 646995
	iscsi_destroy_session(session);
Packit Service 646995
Packit Service 646995
	/* slowly back off the frequency of login attempts */
Packit Service 646995
	if (login_failures == 0)
Packit Service 646995
		login_delay = 0;
Packit Service 646995
	else if (login_failures < 10)
Packit Service 646995
		login_delay = 1;	/* 10 seconds at 1 sec each */
Packit Service 646995
	else if (login_failures < 20)
Packit Service 646995
		login_delay = 2;	/* 20 seconds at 2 sec each */
Packit Service 646995
	else if (login_failures < 26)
Packit Service 646995
		login_delay = 5;	/* 30 seconds at 5 sec each */
Packit Service 646995
	else if (login_failures < 34)
Packit Service 646995
		login_delay = 15;	/* 60 seconds at 15 sec each */
Packit Service 646995
	else
Packit Service 646995
		login_delay = 60;	/* after 2 minutes, try once a minute */
Packit Service 646995
Packit Service 646995
	getnameinfo((struct sockaddr *) &conn->saddr,
Packit Service 646995
		    sizeof(conn->saddr), conn->host,
Packit Service 646995
		    sizeof(conn->host), serv, sizeof(serv),
Packit Service 646995
		    NI_NUMERICHOST|NI_NUMERICSERV);
Packit Service 646995
Packit Service 646995
	if (login_delay) {
Packit Service 646995
		log_debug(4, "discovery session to %s:%s sleeping for %d "
Packit Service 646995
			 "seconds before next login attempt",
Packit Service 646995
			 conn->host, serv, login_delay);
Packit Service 646995
		sleep(login_delay);
Packit Service 646995
	}
Packit Service 646995
	rc = iscsi_create_leading_conn(session);
Packit Service 646995
	if (rc) {
Packit Service 646995
		login_failures++;
Packit Service 646995
		goto reconnect;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(1, "connected to discovery address %s", conn->host);
Packit Service 646995
Packit Service 646995
	log_debug(4, "discovery session to %s:%s starting iSCSI login",
Packit Service 646995
		 conn->host, serv);
Packit Service 646995
Packit Service 646995
	/*
Packit Service 646995
	 * Need to re-init settings because a previous login could
Packit Service 646995
	 * have set them to what was negotiated for.
Packit Service 646995
	 */
Packit Service 646995
	iscsi_copy_operational_params(&session->conn[0], &config->session_conf,
Packit Service 646995
				      &config->conn_conf);
Packit Service 646995
Packit Service 646995
	if (t->caps & CAP_TEXT_NEGO) {
Packit Service 646995
		log_debug(2, "%s discovery set params", __FUNCTION__);
Packit Service 646995
		rc = iscsi_session_set_params(conn);
Packit Service 646995
		if (rc) {
Packit Service 646995
			log_error("Could not set iscsi params for conn %d:%d "
Packit Service 646995
				  "(err %d)", session->id, conn->id, rc);
Packit Service 646995
			rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
			goto login_failed;
Packit Service 646995
		}
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if ((session->t->caps & CAP_LOGIN_OFFLOAD))
Packit Service 646995
		goto start_conn;
Packit Service 646995
Packit Service 646995
	status_class = 0;
Packit Service 646995
	status_detail = 0;
Packit Service 646995
	rc = ISCSI_ERR_LOGIN;
Packit Service 646995
Packit Service 646995
	memset(data, 0, data_len);
Packit Service 646995
	login_status = iscsi_login(session, 0, data, data_len,
Packit Service 646995
				   &status_class, &status_detail);
Packit Service 646995
Packit Service 646995
	switch (login_status) {
Packit Service 646995
	case LOGIN_OK:
Packit Service 646995
	case LOGIN_REDIRECT:
Packit Service 646995
		break;
Packit Service 646995
Packit Service 646995
	case LOGIN_IO_ERROR:
Packit Service 646995
	case LOGIN_REDIRECTION_FAILED:
Packit Service 646995
		/* try again */
Packit Service 646995
		log_warning("retrying discovery login to %s", conn->host);
Packit Service 646995
		login_failures++;
Packit Service 646995
		goto set_address;
Packit Service 646995
Packit Service 646995
	default:
Packit Service 646995
	case LOGIN_FAILED:
Packit Service 646995
	case LOGIN_NEGOTIATION_FAILED:
Packit Service 646995
	case LOGIN_AUTHENTICATION_FAILED:
Packit Service 646995
	case LOGIN_VERSION_MISMATCH:
Packit Service 646995
	case LOGIN_INVALID_PDU:
Packit Service 646995
		log_error("discovery login to %s failed, giving up %d",
Packit Service 646995
			  conn->host, login_status);
Packit Service 646995
		rc = ISCSI_ERR_FATAL_LOGIN;
Packit Service 646995
		goto login_failed;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	/* check the login status */
Packit Service 646995
	switch (status_class) {
Packit Service 646995
	case ISCSI_STATUS_CLS_SUCCESS:
Packit Service 646995
		log_debug(4, "discovery login success to %s", conn->host);
Packit Service 646995
		login_failures = 0;
Packit Service 646995
		break;
Packit Service 646995
	case ISCSI_STATUS_CLS_REDIRECT:
Packit Service 646995
		switch (status_detail) {
Packit Service 646995
			/* the session IP address was changed by the login
Packit Service 646995
			 * library, so just try again with this portal
Packit Service 646995
			 * config but the new address.
Packit Service 646995
			 */
Packit Service 646995
		case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP:
Packit Service 646995
			log_warning(
Packit Service 646995
				"discovery login temporarily redirected to "
Packit Service 646995
				"%s port %s", conn->host, serv);
Packit Service 646995
			goto redirect_reconnect;
Packit Service 646995
		case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM:
Packit Service 646995
			log_warning(
Packit Service 646995
				"discovery login permanently redirected to "
Packit Service 646995
				"%s port %s", conn->host, serv);
Packit Service 646995
			/* make the new address permanent */
Packit Service 646995
			memset(&conn->failback_saddr, 0,
Packit Service 646995
				sizeof(struct sockaddr_storage));
Packit Service 646995
			conn->failback_saddr = conn->saddr;
Packit Service 646995
			goto redirect_reconnect;
Packit Service 646995
		default:
Packit Service 646995
			log_error(
Packit Service 646995
			       "discovery login rejected: redirection type "
Packit Service 646995
			       "0x%x not supported",
Packit Service 646995
			       status_detail);
Packit Service 646995
			goto set_address;
Packit Service 646995
		}
Packit Service 646995
		break;
Packit Service 646995
	case ISCSI_STATUS_CLS_INITIATOR_ERR:
Packit Service 646995
		switch (status_detail) {
Packit Service 646995
		case ISCSI_LOGIN_STATUS_AUTH_FAILED:
Packit Service 646995
		case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN:
Packit Service 646995
			log_error("discovery login to %s rejected: "
Packit Service 646995
				  "initiator failed authorization",
Packit Service 646995
				 conn->host);
Packit Service 646995
			rc = ISCSI_ERR_LOGIN_AUTH_FAILED;
Packit Service 646995
			goto login_failed;
Packit Service 646995
		default:
Packit Service 646995
			log_error("discovery login to %s rejected: initiator "
Packit Service 646995
				  "error (%02x/%02x), non-retryable, giving up",
Packit Service 646995
				  conn->host, status_class, status_detail);
Packit Service 646995
			rc = ISCSI_ERR_FATAL_LOGIN;
Packit Service 646995
		}
Packit Service 646995
		goto login_failed;
Packit Service 646995
	case ISCSI_STATUS_CLS_TARGET_ERR:
Packit Service 646995
		log_error(
Packit Service 646995
			"discovery login to %s rejected: "
Packit Service 646995
			"target error (%02x/%02x)",
Packit Service 646995
			conn->host, status_class, status_detail);
Packit Service 646995
		login_failures++;
Packit Service 646995
		goto reconnect;
Packit Service 646995
	default:
Packit Service 646995
		log_error(
Packit Service 646995
			"discovery login to %s failed, response "
Packit Service 646995
			"with unknown status class 0x%x, detail 0x%x",
Packit Service 646995
			conn->host,
Packit Service 646995
			status_class, status_detail);
Packit Service 646995
		login_failures++;
Packit Service 646995
		goto reconnect;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (!(t->caps & CAP_TEXT_NEGO))
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
start_conn:
Packit Service 646995
	log_debug(2, "%s discovery set neg params", __FUNCTION__);
Packit Service 646995
	rc = iscsi_session_set_neg_params(conn);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("Could not set iscsi params for conn %d:%d (err "
Packit Service 646995
			  "%d)", session->id, conn->id, rc);
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto login_failed;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(2, "%s discovery start conn", __FUNCTION__);
Packit Service 646995
	if (ipc->start_conn(t->handle, session->id, conn->id, &rc) || rc) {
Packit Service 646995
		log_error("Cannot start conn %d:%d (err %d)",
Packit Service 646995
			  session->id, conn->id, rc);
Packit Service 646995
		rc = ISCSI_ERR_INTERNAL;
Packit Service 646995
		goto login_failed;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	rc = iscsi_wait_for_login(conn);
Packit Service 646995
	if (!rc)
Packit Service 646995
		return 0;
Packit Service 646995
Packit Service 646995
login_failed:
Packit Service 646995
	iscsi_destroy_session(session);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
int discovery_sendtargets(void *fndata, struct iface_rec *iface,
Packit Service 646995
			  struct list_head *rec_list)
Packit Service 646995
{
Packit Service 646995
	discovery_rec_t *drec = fndata;
Packit Service 646995
	iscsi_session_t *session;
Packit Service 646995
	struct pollfd pfd;
Packit Service 646995
	struct iscsi_hdr pdu_buffer;
Packit Service 646995
	struct iscsi_hdr *pdu = &pdu_buffer;
Packit Service 646995
	char *data = NULL;
Packit Service 646995
	int active = 0, valid_text = 0;
Packit Service 646995
	struct timeval connection_timer;
Packit Service 646995
	int timeout;
Packit Service 646995
	int rc = 0;
Packit Service 646995
	struct str_buffer sendtargets;
Packit Service 646995
	unsigned int data_len;
Packit Service 646995
	struct iscsi_sendtargets_config *config = &drec->u.sendtargets;
Packit Service 646995
Packit Service 646995
	/* initial setup */
Packit Service 646995
	log_debug(1, "starting sendtargets discovery, address %s:%d, ",
Packit Service 646995
		 drec->address, drec->port);
Packit Service 646995
	memset(&pdu_buffer, 0, sizeof (pdu_buffer));
Packit Service 646995
	iscsi_timer_clear(&connection_timer);
Packit Service 646995
Packit Service 646995
	/* allocate a new session, and initialize default values */
Packit Service 646995
	session = iscsi_alloc_session(config, iface, &rc, drec->iscsid_req_tmo);
Packit Service 646995
	if (rc)
Packit Service 646995
		return rc;
Packit Service 646995
Packit Service 646995
	ipc_ev_context.conn = &session->conn[0];
Packit Service 646995
	ipc_register_ev_callback(&ipc_clbk);
Packit Service 646995
Packit Service 646995
	log_debug(4, "sendtargets discovery to %s:%d using "
Packit Service 646995
		 "isid 0x%02x%02x%02x%02x%02x%02x",
Packit Service 646995
		 drec->address, drec->port, session->isid[0],
Packit Service 646995
		 session->isid[1], session->isid[2], session->isid[3],
Packit Service 646995
		 session->isid[4], session->isid[5]);
Packit Service 646995
Packit Service 646995
	/* allocate data buffers for SendTargets data */
Packit Service 646995
	data = malloc(session->conn[0].max_recv_dlength);
Packit Service 646995
	if (!data) {
Packit Service 646995
		rc = ISCSI_ERR_NOMEM;
Packit Service 646995
		goto free_session;
Packit Service 646995
	}
Packit Service 646995
	data_len = session->conn[0].max_recv_dlength;
Packit Service 646995
Packit Service 646995
	str_init_buffer(&sendtargets, 0);
Packit Service 646995
Packit Service 646995
	/* resolve the DiscoveryAddress to an IP address */
Packit Service 646995
	rc = iscsi_setup_portal(&session->conn[0], drec->address,
Packit Service 646995
				drec->port);
Packit Service 646995
	if (rc) {
Packit Service 646995
		log_error("cannot resolve host name %s", drec->address);
Packit Service 646995
		goto free_sendtargets;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(4, "discovery timeouts: login %d, reopen_cnt %d, auth %d.",
Packit Service 646995
		 session->conn[0].login_timeout, session->reopen_cnt,
Packit Service 646995
		 session->conn[0].auth_timeout);
Packit Service 646995
Packit Service 646995
reconnect:
Packit Service 646995
	rc = iscsi_create_session(session, &drec->u.sendtargets,
Packit Service 646995
				  data, data_len);
Packit Service 646995
	if (rc)
Packit Service 646995
		goto free_sendtargets;
Packit Service 646995
Packit Service 646995
	/* reinitialize */
Packit Service 646995
	str_truncate_buffer(&sendtargets, 0);
Packit Service 646995
Packit Service 646995
	/* ask for targets */
Packit Service 646995
	if (!request_targets(session)) {
Packit Service 646995
		goto reconnect;
Packit Service 646995
	}
Packit Service 646995
	active = 1;
Packit Service 646995
Packit Service 646995
	/* set timeouts */
Packit Service 646995
	iscsi_timer_set(&connection_timer, session->conn[0].active_timeout);
Packit Service 646995
Packit Service 646995
	/* prepare to poll */
Packit Service 646995
	memset(&pfd, 0, sizeof (pfd));
Packit Service 646995
	pfd.fd = session->conn[0].socket_fd;
Packit Service 646995
	pfd.events = POLLIN | POLLPRI;
Packit Service 646995
Packit Service 646995
repoll:
Packit Service 646995
	timeout = iscsi_timer_msecs_until(&connection_timer);
Packit Service 646995
	/* block until we receive a PDU, a TCP FIN, a TCP RST,
Packit Service 646995
	 * or a timeout
Packit Service 646995
	 */
Packit Service 646995
	log_debug(4,
Packit Service 646995
		 "discovery process  %s:%d polling fd %d, "
Packit Service 646995
		 "timeout in %f seconds",
Packit Service 646995
		 drec->address, drec->port, pfd.fd,
Packit Service 646995
		 timeout / 1000.0);
Packit Service 646995
Packit Service 646995
	pfd.revents = 0;
Packit Service 646995
	rc = poll(&pfd, 1, timeout);
Packit Service 646995
Packit Service 646995
	log_debug(7,
Packit Service 646995
		 "discovery process to %s:%d returned from poll, rc %d",
Packit Service 646995
		 drec->address, drec->port, rc);
Packit Service 646995
Packit Service 646995
	if (iscsi_timer_expired(&connection_timer)) {
Packit Service 646995
		log_warning("Discovery session to %s:%d timed out.",
Packit Service 646995
			    drec->address, drec->port);
Packit Service 646995
		rc = ISCSI_ERR_TRANS_TIMEOUT;
Packit Service 646995
		goto reconnect;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	if (rc > 0) {
Packit Service 646995
		if (pfd.revents & (POLLIN | POLLPRI)) {
Packit Service 646995
			timeout = iscsi_timer_msecs_until(&connection_timer);
Packit Service 646995
Packit Service 646995
			rc = iscsi_io_recv_pdu(&session->conn[0],
Packit Service 646995
					        pdu, ISCSI_DIGEST_NONE, data,
Packit Service 646995
					        data_len, ISCSI_DIGEST_NONE,
Packit Service 646995
					        timeout);
Packit Service 646995
			if (rc == -EAGAIN)
Packit Service 646995
				goto repoll;
Packit Service 646995
			else if (rc < 0) {
Packit Service 646995
				log_debug(1, "discovery session to "
Packit Service 646995
					  "%s:%d failed to recv a PDU "
Packit Service 646995
					  "response, terminating",
Packit Service 646995
					   drec->address,
Packit Service 646995
					   drec->port);
Packit Service 646995
				rc = ISCSI_ERR_PDU_TIMEOUT;
Packit Service 646995
				goto free_sendtargets;
Packit Service 646995
			}
Packit Service 646995
Packit Service 646995
			/*
Packit Service 646995
			 * process iSCSI PDU received
Packit Service 646995
			 */
Packit Service 646995
			rc = process_recvd_pdu(pdu, drec, rec_list,
Packit Service 646995
					       session, &sendtargets,
Packit Service 646995
					       &active, &valid_text, data);
Packit Service 646995
			if (rc == (int)DISCOVERY_NEED_RECONNECT)
Packit Service 646995
				goto reconnect;
Packit Service 646995
Packit Service 646995
			/* reset timers after receiving a PDU */
Packit Service 646995
			if (active) {
Packit Service 646995
				iscsi_timer_set(&connection_timer,
Packit Service 646995
				       session->conn[0].active_timeout);
Packit Service 646995
				goto repoll;
Packit Service 646995
			}
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLHUP) {
Packit Service 646995
			log_warning("discovery session to %s:%d "
Packit Service 646995
				    "terminating after hangup",
Packit Service 646995
				     drec->address, drec->port);
Packit Service 646995
			rc = ISCSI_ERR_TRANS;
Packit Service 646995
			goto free_sendtargets;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLNVAL) {
Packit Service 646995
			log_warning("discovery POLLNVAL");
Packit Service 646995
			sleep(1);
Packit Service 646995
			goto reconnect;
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (pfd.revents & POLLERR) {
Packit Service 646995
			log_warning("discovery POLLERR");
Packit Service 646995
			sleep(1);
Packit Service 646995
			goto reconnect;
Packit Service 646995
		}
Packit Service 646995
	} else if (rc < 0) {
Packit Service 646995
		log_error("poll error");
Packit Service 646995
		rc = ISCSI_ERR;
Packit Service 646995
		goto free_sendtargets;
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	log_debug(1, "discovery process to %s:%d exiting",
Packit Service 646995
		 drec->address, drec->port);
Packit Service 646995
	rc = 0;
Packit Service 646995
Packit Service 646995
free_sendtargets:
Packit Service 646995
	str_free_buffer(&sendtargets);
Packit Service 646995
	free(data);
Packit Service 646995
	iscsi_destroy_session(session);
Packit Service 646995
free_session:
Packit Service 646995
	iscsi_free_session(session);
Packit Service 646995
	return rc;
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#ifdef SLP_ENABLE
Packit Service 646995
int
Packit Service 646995
slp_discovery(struct iscsi_slp_config *config)
Packit Service 646995
{
Packit Service 646995
	struct sigaction action;
Packit Service 646995
	char *pl;
Packit Service 646995
	unsigned short flag = 0;
Packit Service 646995
Packit Service 646995
	memset(&action, 0, sizeof (struct sigaction));
Packit Service 646995
	action.sa_sigaction = NULL;
Packit Service 646995
	action.sa_flags = 0;
Packit Service 646995
	action.sa_handler = SIG_DFL;
Packit Service 646995
	sigaction(SIGTERM, &action, NULL);
Packit Service 646995
	sigaction(SIGINT, &action, NULL);
Packit Service 646995
	sigaction(SIGPIPE, &action, NULL);
Packit Service 646995
Packit Service 646995
	action.sa_handler = sighup_handler;
Packit Service 646995
	sigaction(SIGHUP, &action, NULL);
Packit Service 646995
Packit Service 646995
	if (iscsi_process_should_exit()) {
Packit Service 646995
		log_debug(1, "slp discovery process %p exiting", discovery);
Packit Service 646995
		exit(0);
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	discovery->pid = getpid();
Packit Service 646995
Packit Service 646995
	pl = generate_predicate_list(discovery, &flag;;
Packit Service 646995
Packit Service 646995
	while (1) {
Packit Service 646995
		if (flag == SLP_MULTICAST_ENABLED) {
Packit Service 646995
			discovery->flag = SLP_MULTICAST_ENABLED;
Packit Service 646995
			slp_multicast_srv_query(discovery, pl, GENERIC_QUERY);
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		if (flag == SLP_UNICAST_ENABLED) {
Packit Service 646995
			discovery->flag = SLP_UNICAST_ENABLED;
Packit Service 646995
			slp_unicast_srv_query(discovery, pl, GENERIC_QUERY);
Packit Service 646995
		}
Packit Service 646995
Packit Service 646995
		sleep(config->poll_interval);
Packit Service 646995
	}
Packit Service 646995
Packit Service 646995
	exit(0);
Packit Service 646995
}
Packit Service 646995
Packit Service 646995
#endif