NetBSD/sbin/iscsid/iscsid_discover.c
mlelstv 6fea88c26e Several improvents to iscsid
- debug log is now using syslog
- seperate options for log level and foreground mode
- writes a pidfile so that /etc/rc.d/iscsid works
  Now links with libutil for pidfile(), the functions login() and logout()
  needed to be renamed to avoid a conflict.
- drops the nothreads option
- handles signals to shut down gracefully
- the driver may also shut down the daemon when it terminates
  Currently this cannot work as the driver can only terminate when
  the daemon has closed the driver file handle.
2016-05-29 13:35:45 +00:00

930 lines
25 KiB
C

/* $NetBSD: iscsid_discover.c,v 1.5 2016/05/29 13:35:45 mlelstv Exp $ */
/*-
* Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ISCSI_MINIMAL
#include "iscsid_globals.h"
#include "isns.h"
#include "isns_defs.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#define MY_FLAGS ISNS_FLAG_REPLACE_REG
/**********************************************************************
**********************************************************************/
uint32_t isns_id = 0; /* isns ID counter */
ISNS_HANDLE isns_handle = ISNS_INVALID_HANDLE;
/**********************************************************************
**********************************************************************/
/*
* xlate_ip
* Support routine to translate binary IP into string form for storage in
* target object. Handles IPv6 and IPv4 formats.
*
* Parameters:
* dest the destination string
* data the source (from iSNS address field)
*
* Returns: status
*/
static void
xlate_ip(uint8_t *dest, size_t size, void *data)
{
uint16_t *wdt = (uint16_t *) data;
size_t cc;
int i;
char *dst = (char *)dest;
char *dt = data;
for (i = 0; i < 5 && !wdt[i]; i++) {
}
if (i == 5 && wdt[5] == 0xffff) {
snprintf(dst, size, "%d.%d.%d.%d",
dt[12], dt[13], dt[14], dt[15]);
} else {
for (cc = 0, i = 0; i < 7; i++) {
cc += snprintf(&dst[cc], size - cc, "%x:", wdt[i]);
}
snprintf(&dst[cc], size - cc, "%x", wdt[7]);
}
}
/*
* get_isns_target_info
* Support routine to query the server for the attributes of the given target.
*
* Parameters:
* TargetName The target name to query.
*
* Returns: status
*/
static uint32_t
get_isns_target_info(isns_t * isns, uint8_t * TargetName)
{
int retval;
ISNS_TRANS t;
uint32_t tag;
uint32_t data_len;
void *data_p;
uint32_t u32;
struct timespec tout = { 5, 0 };
uint32_t status;
target_t *targ;
char name[ISCSI_STRING_LENGTH];
char alias[ISCSI_STRING_LENGTH];
iscsi_portal_address_t addr;
t = isns_new_trans(isns_handle, isnsp_DevAttrQry, MY_FLAGS);
if (ISNS_INVALID_TRANS == t) {
DEB(10,("%s: get_targets iscsi_new_trans failed", __func__));
return ISCSID_STATUS_NO_RESOURCES;
}
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
isns_add_tlv(t, isnst_Delimiter, 0, NULL);
isns_add_tlv(t, isnst_iSCSIName, 0, NULL); /* 32: name */
isns_add_tlv(t, isnst_iSCSINodeType, 0, NULL); /* 33: node type */
isns_add_tlv(t, isnst_iSCSIAlias, 0, NULL); /* 34: alias */
/* ToDo: get security attributes... */
/* isns_add_tlv (t, isnst_PortalSecBmap, 0, NULL); */
/*tag=27: security bitmap */
retval = isns_send_trans(t, &tout, &status);
DEB(9, ("isns_send_trans called, returns %d, status %d", retval, status));
if (retval) {
DEB(10,("iSNS Attribute Query failed, rc = %d", retval));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
/* First is target name (the one we put in), ignore */
if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
DEB(10,("iSNS Attribute Query returned nothing"));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
if (tag != isnst_iSCSIName) {
DEB(10,("iSNS Query returned bad type (tag = %d, length = %d)",
tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_Delimiter) {
DEB(10,("Attr Query Missing Delimiter (tag = %d, length = %d)",
tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_iSCSIName || !data_len || data_len >= ISCSI_STRING_LENGTH) {
DEB(10,("iSNS Query returned no or invalid name (tag = %d, "
"length = %d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
strlcpy(name, (char *) data_p, sizeof(name));
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_iSCSINodeType || data_len != 4) {
DEB(10,("iSNS Query returned no or invalid node type (tag = %d, "
"length = %d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
u32 = ntohl(*((uint32_t *) data_p));
if (!(u32 & 1)) {
DEB(10,("iSNS Query returned bad type (type=%x, should be 1)", u32));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag == isnst_iSCSIAlias) {
if (data_len >= ISCSI_STRING_LENGTH) {
DEB(10,("iSNS Query returned invalid alias (tag=%d, length=%d)",
tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
strlcpy(alias, (char *) data_p, sizeof(alias));
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
} else
alias[0] = 0;
isns_free_trans(t);
if (ISNS_INVALID_TRANS ==
(t = isns_new_trans(isns_handle, isnsp_DevAttrQry, MY_FLAGS))) {
DEB(10,("get_targets iscsi_new_trans failed"));
return ISCSID_STATUS_NO_RESOURCES;
}
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
isns_add_tlv(t, isnst_Delimiter, 0, NULL);
isns_add_tlv(t, isnst_PGiSCSIName, 0, NULL); /* 48: portal name */
isns_add_tlv(t, isnst_PGPortIPAddr, 0, NULL); /* 49: portal IP */
isns_add_tlv(t, isnst_PGPortIPPort, 0, NULL); /* 50: portal port */
isns_add_tlv(t, isnst_PGTag, 0, NULL); /* 51: group tag */
retval = isns_send_trans(t, &tout, &status);
DEB(9, ("isns_send_trans called, returns %d, status %d", retval, status));
if (retval) {
DEB(10,("iSNS Attribute Query failed, rc = %d", retval));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
/* First is target name (the one we put in), ignore */
if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
DEB(10,("iSNS Attribute Query returned nothing"));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
if (tag != isnst_iSCSIName) {
DEB(10,("iSNS Query2 returned bad name (tag = %d, length = %d)",
tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_Delimiter) {
DEB(10,("Attr Query2 Missing Delimiter (tag = %d, length = %d)",
tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
while (!isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p)) {
if (tag != isnst_PGiSCSIName || !data_len ||
data_len >= ISCSI_STRING_LENGTH) {
DEB(10,("iSNS Query2 returned no or invalid name (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
strlcpy(name, (char *) data_p, sizeof(name));
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_PGPortIPAddr || data_len != 16) {
DEB(10,("iSNS Query returned no or invalid address (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
xlate_ip(addr.address, sizeof(addr.address), (uint8_t *) data_p);
/* Now comes the port */
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_PGPortIPPort || data_len != 4) {
DEB(10,("iSNS Query returned no or invalid port (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
u32 = ntohl(*((uint32_t *) data_p));
if (u32 & 0xffff0000) {
DEB(10,("iSNS Query returned invalid port (flags=%x, "
"should be 0)", u32 >> 16));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
addr.port = (uint16_t) u32;
/* And each target must have a group tag */
isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p);
if (tag != isnst_PGTag || (data_len && data_len != 4)) {
DEB(10,("iSNS Query returned no or invalid group tag (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
return ISCSID_STATUS_ISNS_SERVER_ERROR;
}
if (data_len) {
u32 = ntohl(*((uint32_t *) data_p));
addr.group_tag = (uint16_t) u32;
} else
addr.group_tag = 0;
/* we have everything necessary to describe the target, add it. */
DEB(2, ("Adding <%s>, IP <%s>, Port %d, Tag %d",
name, addr.address, addr.port, addr.group_tag));
if ((targ = add_discovered_target((unsigned char *)name, &addr, PORTAL_TYPE_ISNS,
isns->entry.sid.id)) == NULL) {
isns_free_trans(t);
return ISCSID_STATUS_NO_RESOURCES;
}
if (alias[0]) {
strlcpy((char *)targ->TargetAlias, alias,
sizeof(targ->TargetAlias));
}
}
isns_free_trans(t);
return ISCSID_STATUS_SUCCESS;
}
/*
* deregister_isns_server
* Support routine to deregister the initiator from the iSNS server
*
* Parameters: The server descriptor
*
* Returns: status
*/
static uint32_t
deregister_isns_server(isns_t * isns)
{
int retval;
ISNS_TRANS t;
struct timespec tout = { 5, 0 };
uint32_t status;
/*
* Create transaction for deregistering with iSNS server
*/
if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle, isnsp_DevDereg,
MY_FLAGS))) {
DEB(10,("dereg_isns_server iscsi_new_trans failed"));
return ISCSID_STATUS_NO_RESOURCES;
}
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
isns_add_tlv(t, isnst_Delimiter, 0, NULL);
isns_add_string(t, isnst_EID, (char *)isns->reg_entity_id);
isns_add_tlv(t, isnst_PortalIPAddr, (uint32_t)sizeof(isns->reg_ip_addr),
isns->reg_ip_addr);
isns_add_tlv(t, isnst_PortalPort, (uint32_t)sizeof(isns->reg_ip_port),
&isns->reg_ip_port);
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name);
retval = isns_send_trans(t, &tout, &status);
DEB(9, ("DevAttrReg request returns %d, status %d", retval, status));
isns_free_trans(t);
return ISCSID_STATUS_SUCCESS;
}
/*
* register_isns_server
*
* Parameters: The server descriptor
*
* Returns: status
*/
static uint32_t
register_isns_server(isns_t * isns)
{
int retval;
ISNS_TRANS t;
uint32_t u32;
struct timespec tout = { 5, 0 };
uint32_t status;
if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle, isnsp_DevAttrReg,
MY_FLAGS))) {
DEB(10,("iscsi_new_trans failed"));
return ISCSID_STATUS_NO_RESOURCES;
}
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name); /*tag=32 */
isns_add_tlv(t, isnst_Delimiter, 0, NULL);
isns_add_string(t, isnst_EID, (char *)isns->reg_entity_id);
u32 = htonl(2);
isns_add_tlv(t, isnst_EntProtocol, (uint32_t)sizeof(u32), &u32);
isns_add_tlv(t, isnst_PortalIPAddr, (uint32_t)sizeof(isns->reg_ip_addr),
isns->reg_ip_addr);
isns_add_tlv(t, isnst_PortalPort, (uint32_t)sizeof(isns->reg_ip_port),
&isns->reg_ip_port);
isns_add_string(t, isnst_iSCSIName, (char *)isns->reg_iscsi_name); /*tag=32 */
u32 = htonl(2);
isns_add_tlv(t, isnst_iSCSINodeType, (uint32_t)sizeof(u32), &u32);
/*tag=33 (node type = intiator) */
retval = isns_send_trans(t, &tout, &status);
DEB(9, ("DevAttrReg request returns %d, status %d", retval, status));
isns_free_trans(t);
if (retval || status)
return ISCSID_STATUS_ISNS_ERROR;
return ISCSID_STATUS_SUCCESS;
}
/*
* get_registration_info
*
* Parameters: The server descriptor
*
* Returns: status
*/
static uint32_t
get_registration_info(isns_t * isns)
{
struct sockaddr_storage sa;
unsigned n;
strlcpy((char *)isns->reg_iscsi_name, (char *)node_name.InitiatorName,
sizeof(isns->reg_iscsi_name));
strlcpy((char *)isns->reg_entity_id, (char *)node_name.InitiatorAlias,
sizeof(isns->reg_entity_id));
/*Get our source IP and port numbers */
n = sizeof(sa);
if (getsockname(isns->sock, (struct sockaddr *)(void *)&sa, &n)) {
DEB(10,("Getsockname returned error %d", errno));
return ISCSID_STATUS_GENERAL_ERROR;
}
switch (sa.ss_family) {
case AF_INET:
{
struct sockaddr_in *si =
(struct sockaddr_in *)(void *)&sa;
uint32_t *u32 = (uint32_t *)(void *)isns->reg_ip_addr;
u32[0] = u32[1] = 0;
u32[2] = htonl(0xffff);
u32[3] = htonl(si->sin_addr.s_addr);
isns->reg_ip_port = htons(si->sin_port);
}
break;
case AF_INET6:
{
struct sockaddr_in6 *si =
(struct sockaddr_in6 *)(void *) &sa;
memcpy(isns->reg_ip_addr, &si->sin6_addr,
sizeof(isns->reg_ip_addr));
isns->reg_ip_port = htons(si->sin6_port);
}
break;
default:
DEB(10,("Getsockname returned unknown address family: %d",
sa.ss_family));
return ISCSID_STATUS_GENERAL_ERROR;
}
return ISCSID_STATUS_SUCCESS;
}
/*
* iscsi_isns_serverconn - given a set of server address, try connecting
*
* Parameters: The descriptor for the iSNS server to query
*
* Returns: status
*/
static uint32_t
iscsi_isns_serverconn(isns_t * isns)
{
int sock = -1;
char port[16];
struct addrinfo hints;
struct addrinfo *ai, *addr;
int retval;
/*
* Initialize the iSNS library if it needs it
*/
if (isns_handle == ISNS_INVALID_HANDLE) {
if ((retval = isns_init(&isns_handle, 0)) != 0) {
/*Couldn't initialize the iSNS library */
DEB(10,("isns_init failed with code %d", retval));
isns_handle = ISNS_INVALID_HANDLE;
return ISCSID_STATUS_GENERAL_ERROR;
}
}
/*
* Find the server address from the iSNS server list entry,
* and try to connect to the iSNS server
*/
snprintf(port, sizeof(port), "%d", (isns->port) ? isns->port : ISCSI_DEFAULT_ISNS_PORT);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
retval = getaddrinfo((char *)isns->address, port, &hints, &ai);
if (retval) {
DEB(10,("getaddrinfo failed with code %d (%s)",
retval, gai_strerror(retval)));
return ISCSID_STATUS_GENERAL_ERROR;
}
for (addr = ai; addr != NULL; addr = addr->ai_next) {
sock = socket(addr->ai_family, addr->ai_socktype,
addr->ai_protocol);
if (sock == -1) {
DEB(10,("%s: socket call FAILED!", __func__));
freeaddrinfo(ai);
return (uint32_t)-1;
}
if (connect(sock, addr->ai_addr, addr->ai_addrlen) != -1)
break;
DEB(1, ("%s: connect call FAILED!", __func__));
close(sock);
sock = -1;
}
if (addr == NULL) {
DEB(10,("%s: couldn't connect!", __func__));
freeaddrinfo(ai);
return ISCSID_STATUS_GENERAL_ERROR;
}
if (isns_add_servercon(isns_handle, sock, addr)) {
DEB(10,("%s: FAILED!", __func__));
close(sock);
freeaddrinfo(ai);
return ISCSID_STATUS_GENERAL_ERROR;
}
freeaddrinfo(ai);
isns->sock = sock;
if ((retval = get_registration_info(isns)) != 0) {
return retval;
}
deregister_isns_server(isns);
return register_isns_server(isns);
}
/*
* update_isns_server_info
* Support routine to query the specified iSNS server for all targets
* Called from add_isns_server and refresh_isns_server
*
* Parameters: The descriptor for the iSNS server to query
*
* Returns: status
*/
static uint32_t
update_isns_server_info(isns_t * isns)
{
int retval;
ISNS_TRANS t;
uint32_t tag;
uint32_t data_len;
void *data_p;
uint32_t u32;
struct timespec tout = { 5, 0 };
uint32_t status;
uint8_t TargetName[ISCSI_STRING_LENGTH];
DEB(9, ("update_isns_server_info for iSNS %s", isns->address));
if (isns->sock < 0) {
if ((status = iscsi_isns_serverconn(isns)) != 0) {
/*We couldn't connect to the iSNS server */
DEB(9, ("update_isns_server_info iscsi_isns_serverconn failed"));
return status;
}
}
for (TargetName[0] = 0;;) {
if (ISNS_INVALID_TRANS == (t = isns_new_trans(isns_handle,
isnsp_DevGetNext, MY_FLAGS))) {
DEB(10,("update_isns_server_info iscsi_new_trans failed"));
return ISCSID_STATUS_NO_RESOURCES;
}
isns_add_string(t, isnst_iSCSIName, (char *)node_name.InitiatorName);
if (TargetName[0])
isns_add_string(t, isnst_iSCSIName, (char *)TargetName);
else
isns_add_tlv(t, isnst_iSCSIName, 0, NULL);
isns_add_tlv(t, isnst_Delimiter, 0, NULL);
isns_add_tlv(t, isnst_iSCSINodeType, 0, NULL);
if ((retval = isns_send_trans(t, &tout, &status)) != 0) {
DEB(10,("isns_send_trans returns rc %d, status %d",
retval, status));
isns_free_trans(t);
break;
}
if (status) {
DEB(9, ("DevGetNext Status = %d", status));
break;
}
if (isns_get_tlv(t, ISNS_TLV_FIRST, &tag, &data_len, &data_p)) {
DEB(10,("No TLV in DevGetNext response!"));
isns_free_trans(t);
break;
}
/* We need the name, or there's nothing left to do */
if (tag != isnst_iSCSIName || !data_len ||
data_len >= ISCSI_STRING_LENGTH) {
DEB(10,("iSNS GetNextDev returned no or invalid name (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
break;
}
strlcpy((char *)TargetName, (char *) data_p, sizeof(TargetName));
/* We must get at least the node type, and it must be a target */
if (isns_get_tlv(t, ISNS_TLV_NEXT, &tag, &data_len, &data_p)) {
DEB(10,("iSNS GetDevNext did not return node type"));
isns_free_trans(t);
break;
}
if (tag == isnst_Delimiter && isns_get_tlv(t, ISNS_TLV_NEXT, &tag,
&data_len, &data_p)) {
DEB(10,("iSNS GetDevNext did not return node type (past delim)"));
isns_free_trans(t);
break;
}
if (tag != isnst_iSCSINodeType || data_len != 4) {
DEB(10,("iSNS Query returned no or invalid node type (tag=%d, "
"length=%d)", tag, data_len));
isns_free_trans(t);
break;
}
u32 = ntohl(*((uint32_t *) data_p));
isns_free_trans(t);
if (u32 & 1)
get_isns_target_info(isns, TargetName);
}
DEB(9, ("update_isns_server_info returning SUCCESS!"));
return ISCSID_STATUS_SUCCESS;
}
/**********************************************************************
**********************************************************************/
/*
* create_isns:
* Create an isns structure and initialize it.
*
* Parameter:
* name The iSNS server name
*
* Returns: Pointer to isns structure, NULL if allocation failed.
*/
static isns_t *
create_isns(iscsid_add_isns_server_req_t * req)
{
isns_t *isns;
DEB(9, ("Create iSNS %s", req->address));
if ((isns = calloc(1, sizeof(*isns))) == NULL)
return NULL;
for (isns_id++; !isns_id || find_isns_id(isns_id) != NULL;)
isns_id++;
isns->entry.sid.id = isns_id;
strlcpy((char *)isns->entry.sid.name, (char *)req->name, sizeof(isns->entry.sid.name));
strlcpy((char *)isns->address, (char *)req->address, sizeof(isns->address));
isns->port = req->port;
isns->sock = -1;
return isns;
}
/*
* add_isns_server
* Adds an iSNS server to the server list.
* This command will add the address of an iSNS server to the list
* of iSNS servers that the discovery daemon queries to discover targets.
* The daemon will then register itself with the iSNS server,
* and query the iSNS server for the list of targets.
* The discovered targets will be added to the list of target portals.
* The response contains the ID of the iSNS server.
*
* Parameter: The parameter contains the address of the server.
*
* Returns: Nothing
* The response parameter is an iscsid_add_isns_server_rsp_t
* containing:
* server_id = Unique ID for the iSNS server
*/
void
add_isns_server(iscsid_add_isns_server_req_t * req, iscsid_response_t ** prsp,
int *prsp_temp)
{
iscsid_response_t *rsp = *prsp;
iscsid_add_isns_server_rsp_t *res;
isns_t *isns;
DEB(9, ("IN add_isns_server"));
/*
* Make a response
*/
rsp = make_rsp(sizeof(iscsid_add_isns_server_rsp_t), prsp, prsp_temp);
if (rsp == NULL) {
DEB(9, ("OUT add_isns_server: make_rsp FAILED"));
return;
}
res = (iscsid_add_isns_server_rsp_t *)(void *)rsp->parameter;
/*
* First, allocate the isns server structure to put on the list
*/
isns = create_isns(req);
if (isns == NULL) {
rsp->status = ISCSID_STATUS_NO_RESOURCES;
DEB(9, ("OUT add_isns_server: create_isns FAILED!"));
return;
}
TAILQ_INSERT_TAIL(&list[ISNS_LIST].list, &isns->entry, link);
list[ISNS_LIST].num_entries++;
res->server_id = isns->entry.sid.id;
DEB(9, ("OUT add_isns_server: server_id = %d, name = %s",
isns->entry.sid.id, isns->address));
/*
* Now try to connect to the iSNS server...
*/
update_isns_server_info(isns);
}
/*
* get_isns_server
* Returns the address of the iSNS server with the specified ID
*
* Parameters: The unique ID of the server
*
* Returns: The status returned by the driver
* The response parameter contains the iSNS server address as a
* zero-terminated UTF-8 string
*/
void
get_isns_server(iscsid_sym_id_t * preq, iscsid_response_t ** prsp,
int *prsp_temp)
{
iscsid_response_t *rsp = *prsp;
iscsid_get_isns_server_rsp_t *res;
isns_t *isns;
DEB(9, ("IN get_isns_server"));
isns = find_isns(preq);
if (isns == NULL) {
rsp->status = ISCSID_STATUS_INVALID_ISNS_ID;
DEB(9, ("OUT get_isns_server: find_isns FAILED!"));
return;
}
rsp = make_rsp(sizeof(iscsid_get_isns_server_rsp_t), prsp, prsp_temp);
if (rsp == NULL) {
DEB(9, ("OUT get_isns_server: make_rsp FAILED!"));
return;
}
res = (iscsid_get_isns_server_rsp_t *)(void *)rsp->parameter;
strlcpy((char *)res->address, (char *)isns->address,
sizeof(res->address));
res->port = isns->port;
res->server_id = isns->entry.sid;
DEB(9, ("OUT get_isns_server: id = %d, address = %s",
res->server_id.id, res->address));
}
/*
* slp_find_isns_servers
*/
/* More Here Later... */
/*
* refresh_isns_server
* Query the specified iSNS servers for the list of targets.
*
* Parameters:
* id Server ID
*
* Returns: Status
*/
uint32_t
refresh_isns_server(uint32_t id)
{
uint32_t rc;
isns_t *isns;
generic_entry_t *curr;
generic_entry_t *next;
isns = find_isns_id(id);
if (isns == NULL)
return ISCSID_STATUS_INVALID_ISNS_ID;
TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
portal_t *p = (portal_t *)(void *)curr;
if (p->portaltype == PORTAL_TYPE_ISNS && p->discoveryid == id)
p->portaltype = PORTAL_TYPE_REFRESHING;
}
rc = update_isns_server_info(isns);
/*
* Go through our list of portals and look for ones
* that are still marked for refreshing.
* These are ones that are no longer there and should be removed.
*/
for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
curr = next) {
portal_t *p = (portal_t *)(void *)curr;
next = TAILQ_NEXT(curr, link);
if (p->portaltype == PORTAL_TYPE_REFRESHING)
delete_portal(p, TRUE);
}
return rc;
}
/*
* remove_isns_server
* Removed an iSNS server.
* This does not remove the discovered targets from the list.
*
* Parameters: The iscid_remove_isns_req_t structure containing:
* server_id = unique ID of server to remove
*
* Returns: The status returned.
*/
uint32_t
remove_isns_server(iscsid_sym_id_t * preq)
{
generic_entry_t *curr;
isns_t *isns;
uint32_t id;
isns = find_isns(preq);
if (isns == NULL)
return ISCSID_STATUS_INVALID_ISNS_ID;
/*Deregister with the iSNS server. */
/*Ignore any errors during deregistration... */
if (isns->sock >= 0) {
deregister_isns_server(isns);
close(isns->sock);
}
TAILQ_REMOVE(&list[ISNS_LIST].list, &isns->entry, link);
list[ISNS_LIST].num_entries--;
id = isns->entry.sid.id;
free(isns);
TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
portal_t *p = (portal_t *)(void *)curr;
if (p->portaltype == PORTAL_TYPE_ISNS && p->discoveryid == id)
p->discoveryid = 0; /* mark deleted */
}
return ISCSID_STATUS_SUCCESS;
}
/*
Deregister all isns servers on daemon termination
*/
void
dereg_all_isns_servers(void)
{
generic_list_t *plist;
generic_entry_t *curr;
plist = &list[ISNS_LIST].list;
TAILQ_FOREACH(curr, plist, link)
deregister_isns_server((isns_t *)(void *)curr);
}
#endif