|
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(®->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(®->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
|