/* $NetBSD: iscsid_targets.c,v 1.5 2012/12/29 08:28:20 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 /* 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\n", 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!\n")); 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!\n")); 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\n", 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\n", name)); if ((target = calloc(1, sizeof(*target))) == NULL) { DEBOUT(("Out of memory in create_target!\n")); 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\n", 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\n", 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\n")); } /* * 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\n", 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\n", 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\n", 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)\n", 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\n", 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\n", 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= * TargetAddress=[:], * * 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>\n", 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>\n", 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\n", 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\n", 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; }