NetBSD/sbin/iscsid/iscsid_targets.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

1030 lines
26 KiB
C

/* $NetBSD: iscsid_targets.c,v 1.6 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.
*/
#include "iscsid_globals.h"
#include <ctype.h>
/* counter for portal and target ID */
static uint32_t portarget_id = 0;
/* counter for send_targets ID */
static uint32_t send_target_id = 0;
/*
* create_portal:
* Create a portal entry and link it into the appropriate lists.
* May also create the associated portal group entry if it does not exist.
* Will return the existing entry if the address matches a defined portal.
*
* Parameter:
* target the pointer to the target
* addr the portal address (includes tag)
* dtype portal discovery type
* did discovery ID
*
* Returns: pointer to created portal
*/
static portal_t *
create_portal(target_t *target, iscsi_portal_address_t *addr,
iscsi_portal_types_t dtype, uint32_t did)
{
portal_group_t *curr;
portal_t *portal;
u_short tag = addr->group_tag;
DEB(9, ("Create Portal addr %s port %d group %d",
addr->address, addr->port, addr->group_tag));
if ((portal = find_portal_by_addr(target, addr)) != NULL)
return portal;
portal = calloc(1, sizeof(*portal));
if (!portal) {
DEBOUT(("Out of memory in create_portal!"));
return NULL;
}
portal->addr = *addr;
portal->target = target;
portal->portaltype = dtype;
portal->discoveryid = did;
if (!portal->addr.port) {
portal->addr.port = ISCSI_DEFAULT_PORT;
}
for (portarget_id++; !portarget_id ||
find_portal_id(portarget_id) != NULL ||
find_target_id(TARGET_LIST, portarget_id) != NULL;) {
portarget_id++;
}
portal->entry.sid.id = portarget_id;
TAILQ_FOREACH(curr, &target->group_list, groups)
if (curr->tag == tag)
break;
if (!curr) {
curr = calloc(1, sizeof(*curr));
if (!curr) {
free(portal);
DEBOUT(("Out of memory in create_portal!"));
return NULL;
}
curr->tag = tag;
TAILQ_INIT(&curr->portals);
TAILQ_INSERT_TAIL(&target->group_list, curr, groups);
target->num_groups++;
}
portal->group = curr;
TAILQ_INSERT_TAIL(&curr->portals, portal, group_list);
curr->num_portals++;
target->num_portals++;
TAILQ_INSERT_TAIL(&list[PORTAL_LIST].list, &portal->entry, link);
list[PORTAL_LIST].num_entries++;
DEB(9, ("create_portal returns %p", portal));
return portal;
}
/*
* delete_portal:
* Delete a portal entry after unlinking it from its lists.
* May also delete the associated portal group entry if the group is empty.
*
* Parameter:
* portal the pointer to the portal
* delete_empty delete empty target if true
*/
void
delete_portal(portal_t * portal, boolean_t delete_empty)
{
portal_group_t *curr = portal->group;
target_t *target = portal->target;
TAILQ_REMOVE(&curr->portals, portal, group_list);
TAILQ_REMOVE(&list[PORTAL_LIST].list, &portal->entry, link);
curr->num_portals--;
target->num_portals--;
list[PORTAL_LIST].num_entries--;
if (!curr->num_portals) {
TAILQ_REMOVE(&target->group_list, curr, groups);
free(curr);
target->num_groups--;
}
free(portal);
/* Optionally delete target if no portals left */
if (delete_empty && !target->num_portals) {
TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
list[TARGET_LIST].num_entries--;
free(target);
}
}
/*
* create_target:
* Create a target structure and initialize it.
*
* Parameter:
* name The target name
*
* Returns: Pointer to target structure, NULL if allocation failed.
*/
static target_t *
create_target(uint8_t * name)
{
target_t *target;
DEB(9, ("Create Target %s", name));
if ((target = calloc(1, sizeof(*target))) == NULL) {
DEBOUT(("Out of memory in create_target!"));
return NULL;
}
TAILQ_INIT(&target->group_list);
for (portarget_id++;
!portarget_id ||
find_portal_id(portarget_id) != NULL ||
find_target_id(TARGET_LIST, portarget_id) != NULL;
portarget_id++) {
}
target->entry.sid.id = portarget_id;
strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
return target;
}
/*
* delete_target:
* Delete a target entry after unlinking it from its lists.
* Also deletes all portals associated with the target.
*
* Parameter:
* target the pointer to the target
*/
static void
delete_target(target_t * target)
{
portal_group_t *cgroup;
portal_t *curr = NULL;
/* First delete all portals in all portal groups. */
/* (this will also delete the groups) */
while (target->num_groups) {
cgroup = TAILQ_FIRST(&target->group_list);
while (cgroup && cgroup->num_portals) {
curr = TAILQ_FIRST(&cgroup->portals);
if (curr)
delete_portal(curr, FALSE);
}
}
/*Now delete the target itself */
TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
list[TARGET_LIST].num_entries--;
free(target);
}
/*
* create_send_target:
* Create a send_target structure and initialize it.
*
* Parameter:
* name The target name
* addr The portal address
*
* Returns: Pointer to structure, NULL if allocation failed.
*/
static target_t *
create_send_target(uint8_t * name, iscsi_portal_address_t * addr)
{
send_target_t *target;
DEB(9, ("Create Send Target %s", name));
if ((target = calloc(1, sizeof(*target))) == NULL)
return NULL;
for (send_target_id++;
!send_target_id
|| find_target_id(SEND_TARGETS_LIST, send_target_id) != NULL;)
send_target_id++;
target->entry.sid.id = send_target_id;
strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
target->addr = *addr;
target->num_groups = 1;
target->num_portals = 1;
return (target_t *)(void *)target;
}
/*
* delete_send_target:
* Delete a send_target entry after unlinking it from its lists.
*
* Parameter:
* send_target the pointer to the send_target
*/
static void
delete_send_target(send_target_t * send_target)
{
generic_entry_t *curr;
uint32_t id;
id = send_target->entry.sid.id;
TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
portal_t *p = (void *)curr;
if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
p->discoveryid == id)
p->discoveryid = 0; /* mark deleted */
}
TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link);
list[SEND_TARGETS_LIST].num_entries--;
free(send_target);
}
/*
* add_target:
* Handle ADD_TARGET request: Create a target or send_target and its
* associated portals.
* This routine allows the same target to be defined more than once,
* adding any missing data (for example additional portals).
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp,
int *prsp_temp)
{
iscsid_add_target_rsp_t *res;
iscsid_response_t *rsp = *prsp;
target_t *target, *tn;
portal_t *portal;
int i, num;
DEB(9, ("Add Target, name %s, num_portals %d",
par->TargetName, par->num_portals));
if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) {
rsp->status = ISCSID_STATUS_PARAMETER_INVALID;
return;
}
/* check to see if the target already exists */
if ((par->TargetName[0] &&
(target = find_TargetName(par->list_kind, par->TargetName)) != NULL) ||
(par->list_kind == SEND_TARGETS_LIST &&
(target = (target_t *)(void *)
find_send_target_by_addr(&par->portal[0])) != NULL)) {
num = target->num_portals;
/* symbolic name? */
if (par->sym_name[0]) {
/* already named? rename if OK */
tn = find_target_symname(par->list_kind, par->sym_name);
if (tn && tn != target) {
rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
return;
}
strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name));
}
} else {
if (par->sym_name[0] &&
(find_target_symname(par->list_kind, par->sym_name) ||
find_portal_name(par->sym_name))) {
rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
return;
}
if (par->list_kind == SEND_TARGETS_LIST)
target = create_send_target(par->TargetName, &par->portal[0]);
else
target = create_target(par->TargetName);
if (target == NULL) {
rsp->status = ISCSID_STATUS_NO_RESOURCES;
return;
}
num = 0;
strlcpy((char *)target->entry.sid.name, (char *)par->sym_name,
sizeof(target->entry.sid.name));
}
rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)),
prsp, prsp_temp);
if (rsp == NULL)
return;
res = (iscsid_add_target_rsp_t *)(void *)rsp->parameter;
res->target_id = target->entry.sid.id;
/* link into target list */
if (!num) {
TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry,
link);
list[par->list_kind].num_entries++;
}
/*
Add the given portals. Note that create_portal also checks for
duplicate entries, and returns the pointer to the existing entry
if the request is a duplicate.
*/
if (par->list_kind == SEND_TARGETS_LIST) {
res->portal_id[0] = target->entry.sid.id;
res->num_portals = 1;
} else {
for (i = 0; i < (int)par->num_portals; i++) {
portal = create_portal(target, &par->portal[i],
PORTAL_TYPE_STATIC,
target->entry.sid.id);
if (portal == NULL) {
rsp->status = ISCSID_STATUS_NO_RESOURCES;
break;
}
res->portal_id[i] = portal->entry.sid.id;
}
res->num_portals = i;
}
DEB(9, ("AddTarget returns"));
}
/*
* add_discovered_target:
* Check whether the given target and portal already exist.
* If not, add them.
*
* Parameter:
* TargetName
* portal
* dtype = type of portal added: PORTAL_TYPE_SENDTARGET or
* PORTAL_TYPE_ISNS
* did = ID of SendTargets or iSNS for which portal was discovered
*
* Returns: Pointer to created target, NULL on error (out of memory)
* Always sets portaltype to dtype even if portal already exists
* (used for refreshing to mark portals that we find)
*/
target_t *
add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr,
iscsi_portal_types_t dtype, uint32_t did)
{
target_t *target;
portal_t *portal;
DEB(9, ("Add Discovered Target, name %s, addr %s",
TargetName, addr->address));
if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) {
if ((target = create_target(TargetName)) == NULL) {
return NULL;
}
portal = create_portal(target, addr, dtype, did);
if (portal == NULL) {
free(target);
return NULL;
}
TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link);
list[TARGET_LIST].num_entries++;
} else if ((portal = create_portal(target, addr, dtype, did)) == NULL) {
return NULL;
}
portal->portaltype = dtype;
return target;
}
/*
* set_target_options:
* Handle SET_TARGET_OPTIONS request: Copy the given options into the
* target structure.
*
* Parameter:
* par The request parameters.
*
* Returns: status
*/
uint32_t
set_target_options(iscsid_get_set_target_options_t * par)
{
target_t *target;
if ((target = find_target(par->list_kind, &par->target_id)) == NULL)
return ISCSID_STATUS_INVALID_TARGET_ID;
target->options = *par;
return ISCSID_STATUS_SUCCESS;
}
/*
* set_target_auth:
* Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the
* target structure.
*
* Parameter:
* par The request parameters.
*
* Returns: status
*/
uint32_t
set_target_auth(iscsid_set_target_authentication_req_t * par)
{
target_t *target;
if ((target = find_target(par->list_kind, &par->target_id)) == NULL) {
return ISCSID_STATUS_INVALID_TARGET_ID;
}
target->auth = *par;
return ISCSID_STATUS_SUCCESS;
}
/*
* get_target_info:
* Handle GET_TARGET_INFO request: Return information about the given
* target and its portals. If a portal ID is given, returns only the
* target info and the ID of this portal.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
{
iscsid_get_target_rsp_t *res;
iscsid_response_t *rsp = *prsp;
uint32_t *idp;
target_t *target;
portal_group_t *cgroup;
portal_t *curr = NULL;
int num = 1;
DEB(10, ("get_target_info, id %d", par->id.id));
if ((target = find_target(par->list_kind, &par->id)) == NULL) {
if (par->list_kind == SEND_TARGETS_LIST ||
(curr = find_portal(&par->id)) == NULL) {
rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
return;
}
target = curr->target;
} else if (par->list_kind != SEND_TARGETS_LIST) {
num = target->num_portals;
}
rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t),
prsp, prsp_temp);
if (rsp == NULL)
return;
res = (iscsid_get_target_rsp_t *)(void *)rsp->parameter;
res->target_id = target->entry.sid;
strlcpy((char *)res->TargetName, (char *)target->TargetName,
sizeof(res->TargetName));
strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias,
sizeof(res->TargetAlias));
res->num_portals = num;
idp = res->portal;
if (curr) {
*idp = curr->entry.sid.id;
} else if (par->list_kind != SEND_TARGETS_LIST) {
TAILQ_FOREACH(cgroup, &target->group_list, groups)
TAILQ_FOREACH(curr, &cgroup->portals, group_list)
* idp++ = curr->entry.sid.id;
} else
*idp = target->entry.sid.id;
}
/*
* add_portal:
* Handle ADD_PORTAL request: Add a portal to an existing target.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp,
int *prsp_temp)
{
iscsid_add_portal_rsp_t *res;
iscsid_response_t *rsp = *prsp;
target_t *target;
portal_t *portal;
DEB(9, ("Add portal: target %d (%s), symname %s, addr %s",
par->target_id.id, par->target_id.name,
par->sym_name, par->portal.address));
if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) {
rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
return;
}
if (par->sym_name[0] &&
(find_target_symname(TARGET_LIST, par->sym_name) ||
find_portal_name(par->sym_name))) {
rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
return;
}
portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC,
target->entry.sid.id);
if (portal == NULL) {
rsp->status = ISCSID_STATUS_NO_RESOURCES;
return;
}
if (par->sym_name[0]) {
strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name,
sizeof(portal->entry.sid.name));
}
portal->options = par->options;
rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
if (rsp == NULL)
return;
#if 0 /*XXX: christos res is uninitialized here?? */
res->target_id = target->entry.sid;
res->portal_id = portal->entry.sid;
#endif
DEB(9, ("AddPortal success (id %d)", portal->entry.sid.id));
}
/*
* get_portal_info:
* Handle GET_PORTAL_INFO request: Return information about the given
* portal.
*
* Parameter:
* par The request parameters.
* prsp Pointer to address of response buffer.
* prsp_temp Will be set to TRUE if buffer was allocated, FALSE
* for static buffer.
*/
void
get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
{
iscsid_get_portal_rsp_t *res;
iscsid_response_t *rsp = *prsp;
portal_t *portal = NULL;
send_target_t *starg = NULL;
int err;
DEB(10, ("get_portal_info, id %d", par->id.id));
if (par->list_kind == SEND_TARGETS_LIST)
err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
&par->id)) == NULL);
else
err = ((portal = find_portal(&par->id)) == NULL);
if (err) {
rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID;
return;
}
rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
if (rsp == NULL)
return;
res = (iscsid_get_portal_rsp_t *)(void *)rsp->parameter;
if (par->list_kind == SEND_TARGETS_LIST) {
res->target_id = starg->entry.sid;
res->portal_id = starg->entry.sid;
res->portal = starg->addr;
} else {
res->target_id = portal->target->entry.sid;
res->portal_id = portal->entry.sid;
res->portal = portal->addr;
}
}
/*
* remove_target:
* Handle REMOVE_TARGET request: Removes a target, target portal,
* or Send-Targets portal from its respective list.
* Removing a target will remove all associated portals.
*
* Parameter:
* par The request parameters = iscsid_list_id_t
* containing the target ID.
*
* Returns: status
*/
uint32_t
remove_target(iscsid_list_id_t * par)
{
target_t *target = NULL;
portal_t *portal = NULL;
send_target_t *starg = NULL;
int err;
DEB(9, ("remove_target, id %d", par->id.id));
if (par->list_kind == SEND_TARGETS_LIST) {
err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
&par->id)) == NULL);
if (!err) {
delete_send_target(starg);
}
} else if (par->list_kind == PORTAL_LIST) {
err = ((portal = find_portal(&par->id)) == NULL);
if (!err) {
delete_portal(portal, FALSE);
}
} else {
target = find_target(par->list_kind, &par->id);
err = (target == NULL);
if (!err) {
delete_target(target);
}
}
return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS;
}
/*
* cl_get_address:
* Get an address specification that may include port and group tag.
*
* Parameter:
* portal The portal address
* str The parameter string to scan
*
* Returns: 0 on error, 1 if OK.
*/
static int
cl_get_address(iscsi_portal_address_t * portal, char *str)
{
char *sp, *sp2;
int val;
/* is there a port? don't check inside square brackets (IPv6 addr) */
for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
if (*sp == '[')
val = 1;
else if (*sp == ']')
val = 0;
}
/* */
if (*sp) {
for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
/* if there's a second colon, assume it's an unbracketed IPv6
* address */
if (!*sp2) {
/* truncate source, that's the address */
*sp++ = '\0';
if (sscanf(sp, "%d", &val) != 1)
return 0;
if (val < 0 || val > 0xffff)
return 0;
portal->port = (uint16_t) val;
}
/* is there a group tag? */
for (; isdigit((unsigned char)*sp); sp++) {
}
if (*sp && *sp != ',')
return 0;
} else
for (sp = str + 1; *sp && *sp != ','; sp++);
if (*sp) {
if (sscanf(sp + 1, "%d", &val) != 1)
return 0;
if (val < 0 || val > 0xffff)
return 0;
portal->group_tag = (uint16_t) val;
/* truncate source, that's the address */
*sp = '\0';
}
/* only check length, don't verify correct format (too many
* possibilities) */
if (strlen(str) >= sizeof(portal->address))
return 0;
strlcpy((char *)portal->address, str, sizeof(portal->address));
return 1;
}
/*
* refresh_send_target:
* Handle REFRESH_TARGETS request for a Send Target
*
* Parameter:
* id The send target ID.
*
* Returns: status
*/
static uint32_t
refresh_send_target(uint32_t id)
{
uint8_t *response_buffer = NULL;
uint32_t response_size;
uint32_t ret;
uint8_t *TargetName;
iscsi_portal_address_t addr;
uint8_t *tp, *sp;
generic_entry_t *curr;
generic_entry_t *next;
send_target_t *sendtarg;
int rc;
/*
* Go through our list of portals and mark each one
* belonging to the current sendtargets group to refreshing
* This mark is used afterwards to remove any portals that
* were not refreshed (because the mark gets reset for portals
* that are refreshed).
*/
TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
portal_t *p = (void *)curr;
if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
p->discoveryid == id) {
p->portaltype = PORTAL_TYPE_REFRESHING;
}
}
if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) {
/*
* Parse the response target list
* The SendTargets response in response_buffer is a list of
* target strings. Each target string consists of a TargetName
* string, followed by 0 or more TargetAddress strings:
*
* TargetName=<target-name>
* TargetAddress=<hostname-or-ip>[:<tcp-port>],
* <portal-group-tag>
* The entire list is terminated by a null (after
* response_size bytes) (this terminating NULL was placed
* there by send_targets routine.)
*/
tp = response_buffer;
while (*tp) {
if (strncmp((char *)tp, "TargetName=", 11) != 0) {
DEBOUT(("Response not TargetName <%s>", tp));
break;
}
tp += 11;
TargetName = tp; /*Point to target name */
while (*tp++) {
}
rc = -1; /* Mark no address found yet */
/*Now process any "TargetAddress" entries following */
while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) {
tp += 14;
sp = tp; /* save start of address */
while (*tp++) {
}
/*Get the target address */
rc = cl_get_address(&addr, (char *)sp);
if (rc) {
add_discovered_target(TargetName,
&addr, PORTAL_TYPE_SENDTARGET,
id);
} else {
DEBOUT(("Syntax error in returned target address <%s>", sp));
break;
}
}
if (rc == -1) {
/* There are no TargetAddress entries
* associated with TargetName. This means the
* sendtarget address is used. */
sendtarg = find_send_target_id(id);
if (sendtarg != NULL) {
add_discovered_target(TargetName,
&sendtarg->addr,
PORTAL_TYPE_SENDTARGET, id);
}
}
} /* end of while */
}
/*
* 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 = (void *)curr;
next = TAILQ_NEXT(curr, link);
if (p->portaltype == PORTAL_TYPE_REFRESHING)
delete_portal(p, TRUE);
}
/*
* Clean up
*/
if (response_buffer != NULL)
free(response_buffer);
return ret;
}
/*
* cleanup_send_target_orphans:
* Delete portals that were discovered through a now deleted send target.
*/
static void
cleanup_orphans(iscsi_portal_types_t type)
{
generic_entry_t *curr;
generic_entry_t *next;
/*
* Go through the list of portals and look for ones marked with a zero
* discovery ID, those are associated with send targets that no
* longer exist.
*/
for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
curr = next) {
portal_t *p = (void *)curr;
next = TAILQ_NEXT(curr, link);
if (p->portaltype == type && p->discoveryid == 0) {
delete_portal(p, TRUE);
}
}
}
/*
* refresh_targets:
* Handle REFRESH_TARGETS request:
* Refreshes the list of targets discovered via SendTargets or iSNS
*
* Parameter:
* The request parameter = iscsid_refresh_targets_req_t containing:
* iscsid_list_kind_t kind; Kind:
* SEND_TARGETS_LIST
* ISNS_LIST
* uint32_t num_ids; # of targets in list
* uint32_t id [1]; List of targets
*
* Returns: status
*/
uint32_t
refresh_targets(iscsid_refresh_req_t * par)
{
uint32_t t;
uint32_t rc, retval;
generic_entry_t *curr;
retval = ISCSID_STATUS_NO_TARGETS_FOUND;
switch (par->kind) {
case TARGET_LIST:
/*
* Refreshing for a specific target makes no sense if it's
* static. Maybe implement it for dynamically dicovered
* targets? But then it's best done through the discovering
* instance, or we'll refresh much more than just the given
* target. And refreshing the whole list is iffy as well. So
* refuse this op on the target list for now.
*/
break;
case SEND_TARGETS_LIST:
DEB(9, ("Refresh Send Targets List - num_ids = %d",
par->num_ids));
if (par->num_ids) {
/* Target ids are specified */
for (t = 0; t < par->num_ids; t++) {
rc = refresh_send_target(par->id[t]);
if (rc == 0) {
retval = ISCSID_STATUS_SUCCESS;
}
}
} else {
cleanup_orphans(PORTAL_TYPE_SENDTARGET);
/* No target ids specified - refresh all. */
TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
if ((rc = refresh_send_target(curr->sid.id)) == 0)
retval = ISCSID_STATUS_SUCCESS;
}
return retval;
#ifndef ISCSI_MINIMAL
case ISNS_LIST:
DEB(9, ("Refresh iSNS List - num_ids = %d", par->num_ids));
if (par->num_ids) {
/*Target ids are specified */
for (t = 0; t < par->num_ids; t++)
if ((rc = refresh_isns_server(par->id[t])) == 0)
retval = ISCSI_STATUS_SUCCESS;
} else {
cleanup_orphans(PORTAL_TYPE_ISNS);
/*No target ids specified - refresh all. */
TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
if ((rc = refresh_isns_server(curr->sid.id)) == 0)
retval = ISCSI_STATUS_SUCCESS;
}
return retval;
#endif
default:
break;
}
return ISCSID_STATUS_PARAMETER_INVALID;
}