930 lines
25 KiB
C
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
|
|
|