Home | History | Annotate | Line # | Download | only in iscsid
iscsid_targets.c revision 1.4.2.1
      1  1.4.2.1       tls /*	$NetBSD: iscsid_targets.c,v 1.4.2.1 2013/02/25 00:28:08 tls Exp $	*/
      2      1.1       agc 
      3      1.1       agc /*-
      4      1.1       agc  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
      5      1.1       agc  * All rights reserved.
      6      1.1       agc  *
      7      1.1       agc  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1       agc  * by Wasabi Systems, Inc.
      9      1.1       agc  *
     10      1.1       agc  * Redistribution and use in source and binary forms, with or without
     11      1.1       agc  * modification, are permitted provided that the following conditions
     12      1.1       agc  * are met:
     13      1.1       agc  * 1. Redistributions of source code must retain the above copyright
     14      1.1       agc  *    notice, this list of conditions and the following disclaimer.
     15      1.1       agc  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1       agc  *    notice, this list of conditions and the following disclaimer in the
     17      1.1       agc  *    documentation and/or other materials provided with the distribution.
     18      1.1       agc  *
     19      1.1       agc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.1       agc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.1       agc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.1       agc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.1       agc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.1       agc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.1       agc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.1       agc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.1       agc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.1       agc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.1       agc  * POSSIBILITY OF SUCH DAMAGE.
     30      1.1       agc  */
     31      1.1       agc 
     32      1.1       agc #include "iscsid_globals.h"
     33      1.1       agc 
     34      1.1       agc #include <ctype.h>
     35      1.1       agc 
     36      1.1       agc /* counter for portal and target ID */
     37      1.3       agc static uint32_t portarget_id = 0;
     38      1.1       agc 
     39      1.1       agc /* counter for send_targets ID */
     40      1.3       agc static uint32_t send_target_id = 0;
     41      1.1       agc 
     42      1.1       agc 
     43      1.1       agc /*
     44      1.1       agc  * create_portal:
     45      1.1       agc  *    Create a portal entry and link it into the appropriate lists.
     46      1.1       agc  *    May also create the associated portal group entry if it does not exist.
     47      1.1       agc  *    Will return the existing entry if the address matches a defined portal.
     48      1.1       agc  *
     49      1.1       agc  *    Parameter:
     50      1.1       agc  *       target   the pointer to the target
     51      1.1       agc  *       addr     the portal address (includes tag)
     52      1.1       agc  *		 dtype    portal discovery type
     53      1.1       agc  *		 did	  discovery ID
     54      1.1       agc  *
     55      1.1       agc  *    Returns:    pointer to created portal
     56      1.1       agc  */
     57      1.1       agc 
     58      1.3       agc static portal_t *
     59      1.1       agc create_portal(target_t *target, iscsi_portal_address_t *addr,
     60      1.1       agc 			  iscsi_portal_types_t dtype, uint32_t did)
     61      1.1       agc {
     62      1.1       agc 	portal_group_t *curr;
     63      1.1       agc 	portal_t *portal;
     64      1.1       agc 	u_short tag = addr->group_tag;
     65      1.1       agc 
     66      1.1       agc 	DEB(9, ("Create Portal addr %s port %d group %d\n",
     67      1.1       agc 			addr->address, addr->port, addr->group_tag));
     68      1.1       agc 
     69      1.1       agc 	if ((portal = find_portal_by_addr(target, addr)) != NULL)
     70      1.1       agc 		return portal;
     71      1.1       agc 
     72      1.1       agc 	portal = calloc(1, sizeof(*portal));
     73      1.1       agc 	if (!portal) {
     74      1.1       agc 		DEBOUT(("Out of memory in create_portal!\n"));
     75      1.1       agc 		return NULL;
     76      1.1       agc 	}
     77      1.1       agc 	portal->addr = *addr;
     78      1.1       agc 	portal->target = target;
     79      1.1       agc 	portal->portaltype = dtype;
     80      1.1       agc 	portal->discoveryid = did;
     81      1.1       agc 	if (!portal->addr.port) {
     82      1.1       agc 		portal->addr.port = ISCSI_DEFAULT_PORT;
     83      1.1       agc 	}
     84      1.1       agc 	for (portarget_id++; !portarget_id ||
     85      1.1       agc 	     find_portal_id(portarget_id) != NULL ||
     86      1.1       agc 	     find_target_id(TARGET_LIST, portarget_id) != NULL;) {
     87      1.1       agc 		portarget_id++;
     88      1.1       agc 	}
     89      1.1       agc 	portal->entry.sid.id = portarget_id;
     90      1.1       agc 
     91      1.1       agc 	TAILQ_FOREACH(curr, &target->group_list, groups)
     92      1.1       agc 		if (curr->tag == tag)
     93      1.1       agc 			break;
     94      1.1       agc 
     95      1.1       agc 	if (!curr) {
     96      1.1       agc 		curr = calloc(1, sizeof(*curr));
     97      1.1       agc 		if (!curr) {
     98      1.1       agc 			free(portal);
     99      1.1       agc 			DEBOUT(("Out of memory in create_portal!\n"));
    100      1.1       agc 			return NULL;
    101      1.1       agc 		}
    102      1.1       agc 		curr->tag = tag;
    103      1.1       agc 		TAILQ_INIT(&curr->portals);
    104      1.1       agc 		TAILQ_INSERT_TAIL(&target->group_list, curr, groups);
    105      1.1       agc 		target->num_groups++;
    106      1.1       agc 	}
    107      1.1       agc 
    108      1.1       agc 	portal->group = curr;
    109      1.1       agc 
    110      1.1       agc 	TAILQ_INSERT_TAIL(&curr->portals, portal, group_list);
    111      1.1       agc 	curr->num_portals++;
    112      1.1       agc 	target->num_portals++;
    113      1.1       agc 
    114      1.1       agc 	TAILQ_INSERT_TAIL(&list[PORTAL_LIST].list, &portal->entry, link);
    115      1.1       agc 	list[PORTAL_LIST].num_entries++;
    116      1.1       agc 
    117      1.4       riz 	DEB(9, ("create_portal returns %p\n", portal));
    118      1.1       agc 	return portal;
    119      1.1       agc }
    120      1.1       agc 
    121      1.1       agc 
    122      1.1       agc /*
    123      1.1       agc  * delete_portal:
    124      1.1       agc  *    Delete a portal entry after unlinking it from its lists.
    125      1.1       agc  *    May also delete the associated portal group entry if the group is empty.
    126      1.1       agc  *
    127      1.1       agc  *    Parameter:
    128      1.1       agc  *       portal   		the pointer to the portal
    129      1.1       agc  *		 delete_empty   delete empty target if true
    130      1.1       agc  */
    131      1.1       agc 
    132      1.1       agc void
    133      1.1       agc delete_portal(portal_t * portal, boolean_t delete_empty)
    134      1.1       agc {
    135      1.1       agc 	portal_group_t *curr = portal->group;
    136      1.1       agc 	target_t *target = portal->target;
    137      1.1       agc 
    138      1.1       agc 	TAILQ_REMOVE(&curr->portals, portal, group_list);
    139      1.1       agc 	TAILQ_REMOVE(&list[PORTAL_LIST].list, &portal->entry, link);
    140      1.1       agc 	curr->num_portals--;
    141      1.1       agc 	target->num_portals--;
    142      1.1       agc 	list[PORTAL_LIST].num_entries--;
    143      1.1       agc 
    144      1.1       agc 	if (!curr->num_portals) {
    145      1.1       agc 		TAILQ_REMOVE(&target->group_list, curr, groups);
    146      1.1       agc 		free(curr);
    147      1.1       agc 		target->num_groups--;
    148      1.1       agc 	}
    149      1.1       agc 	free(portal);
    150      1.1       agc 
    151      1.1       agc 	/* Optionally delete target if no portals left */
    152      1.1       agc 	if (delete_empty && !target->num_portals) {
    153      1.1       agc 		TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
    154      1.1       agc 		list[TARGET_LIST].num_entries--;
    155      1.1       agc 		free(target);
    156      1.1       agc 	}
    157      1.1       agc }
    158      1.1       agc 
    159      1.1       agc 
    160      1.1       agc /*
    161      1.1       agc  * create_target:
    162      1.1       agc  *    Create a target structure and initialize it.
    163      1.1       agc  *
    164      1.1       agc  *    Parameter:
    165      1.1       agc  *          name        The target name
    166      1.1       agc  *
    167      1.1       agc  *    Returns:    Pointer to target structure, NULL if allocation failed.
    168      1.1       agc  */
    169      1.1       agc 
    170      1.3       agc static target_t *
    171      1.1       agc create_target(uint8_t * name)
    172      1.1       agc {
    173      1.1       agc 	target_t *target;
    174      1.1       agc 
    175      1.1       agc 	DEB(9, ("Create Target %s\n", name));
    176      1.1       agc 
    177      1.1       agc 	if ((target = calloc(1, sizeof(*target))) == NULL) {
    178      1.1       agc 		DEBOUT(("Out of memory in create_target!\n"));
    179      1.1       agc 		return NULL;
    180      1.1       agc 	}
    181      1.1       agc 
    182      1.1       agc 	TAILQ_INIT(&target->group_list);
    183      1.1       agc 
    184      1.1       agc 	for (portarget_id++;
    185      1.1       agc 	     !portarget_id ||
    186      1.1       agc 	     find_portal_id(portarget_id) != NULL ||
    187      1.1       agc 	     find_target_id(TARGET_LIST, portarget_id) != NULL;
    188      1.1       agc 	     portarget_id++) {
    189      1.1       agc 	}
    190      1.1       agc 
    191      1.1       agc 	target->entry.sid.id = portarget_id;
    192      1.1       agc 	strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
    193      1.1       agc 
    194      1.1       agc 	return target;
    195      1.1       agc }
    196      1.1       agc 
    197      1.1       agc 
    198      1.1       agc /*
    199      1.1       agc  * delete_target:
    200      1.1       agc  *    Delete a target entry after unlinking it from its lists.
    201      1.1       agc  *    Also deletes all portals associated with the target.
    202      1.1       agc  *
    203      1.1       agc  *    Parameter:
    204      1.1       agc  *       target   the pointer to the target
    205      1.1       agc  */
    206      1.1       agc 
    207      1.3       agc static void
    208      1.1       agc delete_target(target_t * target)
    209      1.1       agc {
    210      1.1       agc 	portal_group_t *cgroup;
    211      1.1       agc 	portal_t *curr = NULL;
    212      1.1       agc 
    213      1.1       agc 	/* First delete all portals in all portal groups. */
    214      1.1       agc 	/* (this will also delete the groups) */
    215      1.1       agc 	while (target->num_groups) {
    216      1.1       agc 		cgroup = TAILQ_FIRST(&target->group_list);
    217      1.1       agc 		while (cgroup && cgroup->num_portals) {
    218      1.1       agc 			curr = TAILQ_FIRST(&cgroup->portals);
    219      1.1       agc 			if (curr)
    220      1.1       agc 				delete_portal(curr, FALSE);
    221      1.1       agc 		}
    222      1.1       agc 	}
    223      1.1       agc 
    224      1.1       agc 	/*Now delete the target itself */
    225      1.1       agc 	TAILQ_REMOVE(&list[TARGET_LIST].list, &target->entry, link);
    226      1.1       agc 	list[TARGET_LIST].num_entries--;
    227      1.1       agc 	free(target);
    228      1.1       agc }
    229      1.1       agc 
    230      1.1       agc 
    231      1.1       agc /*
    232      1.1       agc  * create_send_target:
    233      1.1       agc  *    Create a send_target structure and initialize it.
    234      1.1       agc  *
    235      1.1       agc  *    Parameter:
    236      1.1       agc  *          name        The target name
    237      1.1       agc  *          addr        The portal address
    238      1.1       agc  *
    239      1.1       agc  *    Returns:    Pointer to structure, NULL if allocation failed.
    240      1.1       agc  */
    241      1.1       agc 
    242      1.3       agc static target_t *
    243      1.1       agc create_send_target(uint8_t * name, iscsi_portal_address_t * addr)
    244      1.1       agc {
    245      1.1       agc 	send_target_t *target;
    246      1.1       agc 
    247      1.1       agc 	DEB(9, ("Create Send Target %s\n", name));
    248      1.1       agc 
    249      1.1       agc 	if ((target = calloc(1, sizeof(*target))) == NULL)
    250      1.1       agc 		return NULL;
    251      1.1       agc 
    252      1.1       agc 	for (send_target_id++;
    253      1.1       agc 		 !send_target_id
    254      1.1       agc 		 || find_target_id(SEND_TARGETS_LIST, send_target_id) != NULL;)
    255      1.1       agc 		send_target_id++;
    256      1.1       agc 
    257      1.1       agc 	target->entry.sid.id = send_target_id;
    258      1.1       agc 	strlcpy((char *)target->TargetName, (char *)name, sizeof(target->TargetName));
    259      1.1       agc 	target->addr = *addr;
    260      1.1       agc 	target->num_groups = 1;
    261      1.1       agc 	target->num_portals = 1;
    262      1.1       agc 
    263      1.2  christos 	return (target_t *)(void *)target;
    264      1.1       agc }
    265      1.1       agc 
    266      1.1       agc /*
    267      1.1       agc  * delete_send_target:
    268      1.1       agc  *    Delete a send_target entry after unlinking it from its lists.
    269      1.1       agc  *
    270      1.1       agc  *    Parameter:
    271      1.1       agc  *       send_target   the pointer to the send_target
    272      1.1       agc  */
    273      1.1       agc 
    274      1.3       agc static void
    275      1.1       agc delete_send_target(send_target_t * send_target)
    276      1.1       agc {
    277      1.1       agc 	generic_entry_t *curr;
    278      1.1       agc 	uint32_t id;
    279      1.1       agc 
    280      1.1       agc 	id = send_target->entry.sid.id;
    281      1.1       agc 
    282      1.1       agc 	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
    283      1.2  christos 		portal_t *p = (void *)curr;
    284      1.2  christos 		if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
    285      1.2  christos 			p->discoveryid == id)
    286      1.2  christos 			p->discoveryid = 0; /* mark deleted */
    287      1.1       agc 	}
    288      1.1       agc 
    289      1.1       agc 	TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link);
    290      1.1       agc 	list[SEND_TARGETS_LIST].num_entries--;
    291      1.1       agc 	free(send_target);
    292      1.1       agc }
    293      1.1       agc 
    294      1.1       agc 
    295      1.1       agc 
    296      1.1       agc /*
    297      1.1       agc  * add_target:
    298      1.1       agc  *    Handle ADD_TARGET request: Create a target or send_target and its
    299      1.1       agc  *    associated portals.
    300      1.1       agc  *    This routine allows the same target to be defined more than once,
    301      1.1       agc  *    adding any missing data (for example additional portals).
    302      1.1       agc  *
    303      1.1       agc  *    Parameter:
    304      1.1       agc  *          par         The request parameters.
    305      1.1       agc  *          prsp        Pointer to address of response buffer.
    306      1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    307      1.1       agc  *                      for static buffer.
    308      1.1       agc  */
    309      1.1       agc 
    310      1.1       agc 
    311      1.1       agc void
    312      1.1       agc add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp,
    313      1.1       agc 			int *prsp_temp)
    314      1.1       agc {
    315      1.1       agc 	iscsid_add_target_rsp_t *res;
    316      1.1       agc 	iscsid_response_t *rsp = *prsp;
    317      1.1       agc 	target_t *target, *tn;
    318      1.1       agc 	portal_t *portal;
    319      1.1       agc 	int i, num;
    320      1.1       agc 
    321      1.1       agc 	DEB(9, ("Add Target, name %s, num_portals %d\n",
    322      1.1       agc 			par->TargetName, par->num_portals));
    323      1.1       agc 
    324      1.1       agc 	if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) {
    325      1.1       agc 		rsp->status = ISCSID_STATUS_PARAMETER_INVALID;
    326      1.1       agc 		return;
    327      1.1       agc 	}
    328      1.1       agc 	/* check to see if the target already exists */
    329      1.1       agc 	if ((par->TargetName[0] &&
    330      1.1       agc 	     (target = find_TargetName(par->list_kind, par->TargetName)) != NULL) ||
    331      1.1       agc 	    (par->list_kind == SEND_TARGETS_LIST &&
    332      1.2  christos 	     (target = (target_t *)(void *)
    333      1.1       agc 			find_send_target_by_addr(&par->portal[0])) != NULL)) {
    334      1.1       agc 		num = target->num_portals;
    335      1.1       agc 
    336      1.1       agc 		/* symbolic name? */
    337      1.1       agc 		if (par->sym_name[0]) {
    338      1.1       agc 			/* already named? rename if OK */
    339      1.1       agc 			tn = find_target_symname(par->list_kind, par->sym_name);
    340      1.1       agc 			if (tn && tn != target) {
    341      1.1       agc 				rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    342      1.1       agc 				return;
    343      1.1       agc 			}
    344      1.1       agc 			strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name));
    345      1.1       agc 		}
    346      1.1       agc 	} else {
    347      1.1       agc 		if (par->sym_name[0] &&
    348      1.1       agc 			(find_target_symname(par->list_kind, par->sym_name) ||
    349      1.1       agc 			 find_portal_name(par->sym_name))) {
    350      1.1       agc 			rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    351      1.1       agc 			return;
    352      1.1       agc 		}
    353      1.1       agc 
    354      1.1       agc 		if (par->list_kind == SEND_TARGETS_LIST)
    355      1.1       agc 			target = create_send_target(par->TargetName, &par->portal[0]);
    356      1.1       agc 		else
    357      1.1       agc 			target = create_target(par->TargetName);
    358      1.1       agc 
    359      1.1       agc 		if (target == NULL) {
    360      1.1       agc 			rsp->status = ISCSID_STATUS_NO_RESOURCES;
    361      1.1       agc 			return;
    362      1.1       agc 		}
    363      1.1       agc 		num = 0;
    364      1.1       agc 		strlcpy((char *)target->entry.sid.name, (char *)par->sym_name,
    365      1.1       agc 			sizeof(target->entry.sid.name));
    366      1.1       agc 	}
    367      1.1       agc 
    368      1.1       agc 	rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)),
    369      1.1       agc 			prsp, prsp_temp);
    370      1.1       agc 	if (rsp == NULL)
    371      1.1       agc 		return;
    372      1.1       agc 
    373      1.2  christos 	res = (iscsid_add_target_rsp_t *)(void *)rsp->parameter;
    374      1.1       agc 	res->target_id = target->entry.sid.id;
    375      1.1       agc 
    376      1.1       agc 	/* link into target list */
    377      1.1       agc 	if (!num) {
    378      1.1       agc 		TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry,
    379      1.1       agc 			link);
    380      1.1       agc 		list[par->list_kind].num_entries++;
    381      1.1       agc 	}
    382      1.1       agc 
    383      1.1       agc 	/*
    384      1.1       agc 	   Add the given portals. Note that create_portal also checks for
    385      1.1       agc 	   duplicate entries, and returns the pointer to the existing entry
    386      1.1       agc 	   if the request is a duplicate.
    387      1.1       agc 	 */
    388      1.1       agc 
    389      1.1       agc 	if (par->list_kind == SEND_TARGETS_LIST) {
    390      1.1       agc 		res->portal_id[0] = target->entry.sid.id;
    391      1.1       agc 		res->num_portals = 1;
    392      1.1       agc 	} else {
    393      1.1       agc 		for (i = 0; i < (int)par->num_portals; i++) {
    394      1.1       agc 			portal = create_portal(target, &par->portal[i],
    395      1.1       agc 					PORTAL_TYPE_STATIC,
    396      1.1       agc 					target->entry.sid.id);
    397      1.1       agc 			if (portal == NULL) {
    398      1.1       agc 				rsp->status = ISCSID_STATUS_NO_RESOURCES;
    399      1.1       agc 				break;
    400      1.1       agc 			}
    401      1.1       agc 			res->portal_id[i] = portal->entry.sid.id;
    402      1.1       agc 		}
    403      1.1       agc 		res->num_portals = i;
    404      1.1       agc 	}
    405      1.1       agc 
    406      1.1       agc 	DEB(9, ("AddTarget returns\n"));
    407      1.1       agc }
    408      1.1       agc 
    409      1.1       agc 
    410      1.1       agc /*
    411      1.1       agc  * add_discovered_target:
    412      1.1       agc  *    Check whether the given target and portal already exist.
    413      1.1       agc  *    If not, add them.
    414      1.1       agc  *
    415      1.1       agc  *    Parameter:
    416      1.1       agc  *          TargetName
    417      1.1       agc  *          portal
    418      1.1       agc  *          dtype = type of portal added: PORTAL_TYPE_SENDTARGET or
    419      1.1       agc  *					PORTAL_TYPE_ISNS
    420      1.1       agc  *          did = ID of SendTargets or iSNS for which portal was discovered
    421      1.1       agc  *
    422      1.1       agc  *    Returns: Pointer to created target, NULL on error (out of memory)
    423      1.1       agc  *    Always sets portaltype to dtype even if portal already exists
    424      1.1       agc  *      (used for refreshing to mark portals that we find)
    425      1.1       agc  */
    426      1.1       agc 
    427      1.1       agc target_t *
    428      1.1       agc add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr,
    429      1.1       agc 				iscsi_portal_types_t dtype, uint32_t did)
    430      1.1       agc {
    431      1.1       agc 	target_t *target;
    432      1.1       agc 	portal_t *portal;
    433      1.1       agc 
    434      1.1       agc 	DEB(9, ("Add Discovered Target, name %s, addr %s\n",
    435      1.1       agc 			TargetName, addr->address));
    436      1.1       agc 
    437      1.1       agc 	if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) {
    438      1.1       agc 		if ((target = create_target(TargetName)) == NULL) {
    439      1.1       agc 			return NULL;
    440      1.1       agc 		}
    441      1.1       agc 		portal = create_portal(target, addr, dtype, did);
    442      1.1       agc 		if (portal == NULL) {
    443      1.1       agc 			free(target);
    444      1.1       agc 			return NULL;
    445      1.1       agc 		}
    446      1.1       agc 		TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link);
    447      1.1       agc 		list[TARGET_LIST].num_entries++;
    448      1.1       agc 	} else if ((portal = create_portal(target, addr, dtype, did)) == NULL) {
    449      1.1       agc 		return NULL;
    450      1.1       agc 	}
    451      1.1       agc 	portal->portaltype = dtype;
    452      1.1       agc 
    453      1.1       agc 	return target;
    454      1.1       agc }
    455      1.1       agc 
    456      1.1       agc 
    457      1.1       agc /*
    458      1.1       agc  * set_target_options:
    459      1.1       agc  *    Handle SET_TARGET_OPTIONS request: Copy the given options into the
    460      1.1       agc  *    target structure.
    461      1.1       agc  *
    462      1.1       agc  *    Parameter:
    463      1.1       agc  *          par         The request parameters.
    464      1.1       agc  *
    465      1.1       agc  *    Returns:     status
    466      1.1       agc  */
    467      1.1       agc 
    468      1.1       agc uint32_t
    469      1.1       agc set_target_options(iscsid_get_set_target_options_t * par)
    470      1.1       agc {
    471      1.1       agc 	target_t *target;
    472      1.1       agc 
    473      1.1       agc 	if ((target = find_target(par->list_kind, &par->target_id)) == NULL)
    474      1.1       agc 		return ISCSID_STATUS_INVALID_TARGET_ID;
    475      1.1       agc 
    476      1.1       agc 	target->options = *par;
    477      1.1       agc 
    478      1.1       agc 	return ISCSID_STATUS_SUCCESS;
    479      1.1       agc }
    480      1.1       agc 
    481      1.1       agc 
    482      1.1       agc /*
    483      1.1       agc  * set_target_auth:
    484      1.1       agc  *    Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the
    485      1.1       agc  *    target structure.
    486      1.1       agc  *
    487      1.1       agc  *    Parameter:
    488      1.1       agc  *          par         The request parameters.
    489      1.1       agc  *
    490      1.1       agc  *    Returns:     status
    491      1.1       agc  */
    492      1.1       agc 
    493      1.1       agc uint32_t
    494      1.1       agc set_target_auth(iscsid_set_target_authentication_req_t * par)
    495      1.1       agc {
    496      1.1       agc 	target_t *target;
    497      1.1       agc 
    498      1.1       agc 	if ((target = find_target(par->list_kind, &par->target_id)) == NULL) {
    499      1.1       agc 		return ISCSID_STATUS_INVALID_TARGET_ID;
    500      1.1       agc 	}
    501      1.1       agc 	target->auth = *par;
    502      1.1       agc 
    503      1.1       agc 	return ISCSID_STATUS_SUCCESS;
    504      1.1       agc }
    505      1.1       agc 
    506      1.1       agc 
    507      1.1       agc /*
    508      1.1       agc  * get_target_info:
    509      1.1       agc  *    Handle GET_TARGET_INFO request: Return information about the given
    510      1.1       agc  *    target and its portals. If a portal ID is given, returns only the
    511      1.1       agc  *    target info and the ID of this portal.
    512      1.1       agc  *
    513      1.1       agc  *    Parameter:
    514      1.1       agc  *          par         The request parameters.
    515      1.1       agc  *          prsp        Pointer to address of response buffer.
    516      1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    517      1.1       agc  *                      for static buffer.
    518      1.1       agc  */
    519      1.1       agc 
    520      1.1       agc void
    521      1.1       agc get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
    522      1.1       agc {
    523      1.1       agc 	iscsid_get_target_rsp_t *res;
    524      1.1       agc 	iscsid_response_t *rsp = *prsp;
    525      1.1       agc 	uint32_t *idp;
    526      1.1       agc 	target_t *target;
    527      1.1       agc 	portal_group_t *cgroup;
    528      1.1       agc 	portal_t *curr = NULL;
    529      1.1       agc 	int num = 1;
    530      1.1       agc 
    531      1.1       agc 	DEB(10, ("get_target_info, id %d\n", par->id.id));
    532      1.1       agc 
    533      1.1       agc 	if ((target = find_target(par->list_kind, &par->id)) == NULL) {
    534      1.1       agc 		if (par->list_kind == SEND_TARGETS_LIST ||
    535      1.1       agc 		    (curr = find_portal(&par->id)) == NULL) {
    536      1.1       agc 			rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
    537      1.1       agc 			return;
    538      1.1       agc 		}
    539      1.1       agc 		target = curr->target;
    540      1.1       agc 	} else if (par->list_kind != SEND_TARGETS_LIST) {
    541      1.1       agc 		num = target->num_portals;
    542      1.1       agc 	}
    543      1.1       agc 	rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t),
    544      1.1       agc 			prsp, prsp_temp);
    545      1.1       agc 	if (rsp == NULL)
    546      1.1       agc 		return;
    547      1.1       agc 
    548      1.2  christos 	res = (iscsid_get_target_rsp_t *)(void *)rsp->parameter;
    549      1.1       agc 	res->target_id = target->entry.sid;
    550      1.1       agc 	strlcpy((char *)res->TargetName, (char *)target->TargetName,
    551      1.1       agc 			sizeof(res->TargetName));
    552      1.1       agc 	strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias,
    553      1.1       agc 			sizeof(res->TargetAlias));
    554      1.1       agc 
    555      1.1       agc 	res->num_portals = num;
    556      1.1       agc 	idp = res->portal;
    557      1.1       agc 
    558      1.1       agc 	if (curr) {
    559      1.1       agc 		*idp = curr->entry.sid.id;
    560      1.1       agc 	} else if (par->list_kind != SEND_TARGETS_LIST) {
    561      1.1       agc 		TAILQ_FOREACH(cgroup, &target->group_list, groups)
    562      1.1       agc 			TAILQ_FOREACH(curr, &cgroup->portals, group_list)
    563      1.1       agc 			* idp++ = curr->entry.sid.id;
    564      1.1       agc 	} else
    565      1.1       agc 		*idp = target->entry.sid.id;
    566      1.1       agc }
    567      1.1       agc 
    568      1.1       agc 
    569      1.1       agc /*
    570      1.1       agc  * add_portal:
    571      1.1       agc  *    Handle ADD_PORTAL request: Add a portal to an existing target.
    572      1.1       agc  *
    573      1.1       agc  *    Parameter:
    574      1.1       agc  *          par         The request parameters.
    575      1.1       agc  *          prsp        Pointer to address of response buffer.
    576      1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    577      1.1       agc  *                      for static buffer.
    578      1.1       agc  */
    579      1.1       agc 
    580      1.1       agc 
    581      1.1       agc void
    582      1.1       agc add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp,
    583      1.1       agc 			int *prsp_temp)
    584      1.1       agc {
    585      1.1       agc 	iscsid_add_portal_rsp_t *res;
    586      1.1       agc 	iscsid_response_t *rsp = *prsp;
    587      1.1       agc 	target_t *target;
    588      1.1       agc 	portal_t *portal;
    589      1.1       agc 
    590      1.1       agc 	DEB(9, ("Add portal: target %d (%s), symname %s, addr %s\n",
    591      1.1       agc 			par->target_id.id, par->target_id.name,
    592      1.1       agc 			par->sym_name, par->portal.address));
    593      1.1       agc 
    594      1.1       agc 	if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) {
    595      1.1       agc 		rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
    596      1.1       agc 		return;
    597      1.1       agc 	}
    598      1.1       agc 
    599      1.1       agc 	if (par->sym_name[0] &&
    600      1.1       agc 		(find_target_symname(TARGET_LIST, par->sym_name) ||
    601      1.1       agc 		 find_portal_name(par->sym_name))) {
    602      1.1       agc 		rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    603      1.1       agc 		return;
    604      1.1       agc 	}
    605      1.1       agc 
    606      1.1       agc 	portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC,
    607      1.1       agc 							target->entry.sid.id);
    608      1.1       agc 	if (portal == NULL) {
    609      1.1       agc 		rsp->status = ISCSID_STATUS_NO_RESOURCES;
    610      1.1       agc 		return;
    611      1.1       agc 	}
    612      1.1       agc 
    613      1.1       agc 	if (par->sym_name[0]) {
    614      1.1       agc 		strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name,
    615      1.1       agc 			sizeof(portal->entry.sid.name));
    616      1.1       agc 	}
    617      1.1       agc 	portal->options = par->options;
    618      1.1       agc 
    619      1.1       agc 	rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
    620      1.1       agc 	if (rsp == NULL)
    621      1.1       agc 		return;
    622      1.2  christos #if 0 /*XXX: christos res is uninitialized here?? */
    623      1.1       agc 	res->target_id = target->entry.sid;
    624      1.1       agc 	res->portal_id = portal->entry.sid;
    625      1.2  christos #endif
    626      1.1       agc 
    627      1.1       agc 	DEB(9, ("AddPortal success (id %d)\n", portal->entry.sid.id));
    628      1.1       agc }
    629      1.1       agc 
    630      1.1       agc 
    631      1.1       agc /*
    632      1.1       agc  * get_portal_info:
    633      1.1       agc  *    Handle GET_PORTAL_INFO request: Return information about the given
    634      1.1       agc  *    portal.
    635      1.1       agc  *
    636      1.1       agc  *    Parameter:
    637      1.1       agc  *          par         The request parameters.
    638      1.1       agc  *          prsp        Pointer to address of response buffer.
    639      1.1       agc  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    640      1.1       agc  *                      for static buffer.
    641      1.1       agc  */
    642      1.1       agc 
    643      1.1       agc void
    644      1.1       agc get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
    645      1.1       agc {
    646      1.1       agc 	iscsid_get_portal_rsp_t *res;
    647      1.1       agc 	iscsid_response_t *rsp = *prsp;
    648      1.1       agc 	portal_t *portal = NULL;
    649      1.1       agc 	send_target_t *starg = NULL;
    650      1.1       agc 	int err;
    651      1.1       agc 
    652      1.1       agc 	DEB(10, ("get_portal_info, id %d\n", par->id.id));
    653      1.1       agc 
    654      1.1       agc 	if (par->list_kind == SEND_TARGETS_LIST)
    655      1.2  christos 		err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
    656      1.1       agc 							&par->id)) == NULL);
    657      1.1       agc 	else
    658      1.1       agc 		err = ((portal = find_portal(&par->id)) == NULL);
    659      1.1       agc 
    660      1.1       agc 	if (err) {
    661      1.1       agc 		rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID;
    662      1.1       agc 		return;
    663      1.1       agc 	}
    664      1.1       agc 
    665      1.1       agc 	rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
    666      1.1       agc 	if (rsp == NULL)
    667      1.1       agc 		return;
    668      1.1       agc 
    669      1.2  christos 	res = (iscsid_get_portal_rsp_t *)(void *)rsp->parameter;
    670      1.1       agc 	if (par->list_kind == SEND_TARGETS_LIST) {
    671      1.1       agc 		res->target_id = starg->entry.sid;
    672      1.1       agc 		res->portal_id = starg->entry.sid;
    673      1.1       agc 		res->portal = starg->addr;
    674      1.1       agc 	} else {
    675      1.1       agc 		res->target_id = portal->target->entry.sid;
    676      1.1       agc 		res->portal_id = portal->entry.sid;
    677      1.1       agc 		res->portal = portal->addr;
    678      1.1       agc 	}
    679      1.1       agc }
    680      1.1       agc 
    681      1.1       agc /*
    682      1.1       agc  * remove_target:
    683      1.1       agc  *    Handle REMOVE_TARGET request: Removes a target, target portal,
    684      1.1       agc  *		or Send-Targets portal from its respective list.
    685      1.1       agc  *      Removing a target will remove all associated portals.
    686      1.1       agc  *
    687      1.1       agc  *    Parameter:
    688      1.1       agc  *          par         The request parameters = iscsid_list_id_t
    689      1.1       agc  *						containing the target ID.
    690      1.1       agc  *
    691      1.1       agc  *    Returns:     status
    692      1.1       agc  */
    693      1.1       agc 
    694      1.1       agc uint32_t
    695      1.1       agc remove_target(iscsid_list_id_t * par)
    696      1.1       agc {
    697      1.1       agc 	target_t *target = NULL;
    698      1.1       agc 	portal_t *portal = NULL;
    699      1.1       agc 	send_target_t *starg = NULL;
    700      1.1       agc 	int err;
    701      1.1       agc 
    702      1.1       agc 	DEB(9, ("remove_target, id %d\n", par->id.id));
    703      1.1       agc 
    704      1.1       agc 	if (par->list_kind == SEND_TARGETS_LIST) {
    705      1.2  christos 		err = ((starg = (send_target_t *)(void *)find_target(par->list_kind,
    706      1.1       agc 							&par->id)) == NULL);
    707      1.1       agc 		if (!err) {
    708      1.1       agc 			delete_send_target(starg);
    709      1.1       agc 		}
    710      1.1       agc 	} else if (par->list_kind == PORTAL_LIST) {
    711      1.1       agc 		err = ((portal = find_portal(&par->id)) == NULL);
    712      1.1       agc 		if (!err) {
    713      1.1       agc 			delete_portal(portal, FALSE);
    714      1.1       agc 		}
    715      1.1       agc 	} else {
    716      1.1       agc 		target = find_target(par->list_kind, &par->id);
    717      1.1       agc 		err = (target == NULL);
    718      1.1       agc 		if (!err) {
    719      1.1       agc 			delete_target(target);
    720      1.1       agc 		}
    721      1.1       agc 	}
    722      1.1       agc 
    723      1.1       agc 	return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS;
    724      1.1       agc }
    725      1.1       agc 
    726      1.1       agc 
    727      1.1       agc 
    728      1.1       agc /*
    729      1.1       agc  * cl_get_address:
    730      1.1       agc  *    Get an address specification that may include port and group tag.
    731      1.1       agc  *
    732      1.1       agc  *    Parameter:
    733      1.1       agc  *          portal   The portal address
    734      1.1       agc  *          str      The parameter string to scan
    735      1.1       agc  *
    736      1.1       agc  *    Returns:    0 on error, 1 if OK.
    737      1.1       agc  */
    738      1.1       agc 
    739      1.3       agc static int
    740      1.1       agc cl_get_address(iscsi_portal_address_t * portal, char *str)
    741      1.1       agc {
    742      1.1       agc 	char *sp, *sp2;
    743      1.1       agc 	int val;
    744      1.1       agc 
    745      1.1       agc 	/* is there a port? don't check inside square brackets (IPv6 addr) */
    746      1.1       agc 	for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
    747      1.1       agc 		if (*sp == '[')
    748      1.1       agc 			val = 1;
    749      1.1       agc 		else if (*sp == ']')
    750      1.1       agc 			val = 0;
    751      1.1       agc 	}
    752      1.1       agc 
    753      1.1       agc 	/* */
    754      1.1       agc 	if (*sp) {
    755      1.1       agc 		for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
    756      1.1       agc 		/* if there's a second colon, assume it's an unbracketed IPv6
    757      1.1       agc 		 * address */
    758      1.1       agc 		if (!*sp2) {
    759      1.1       agc 			/* truncate source, that's the address */
    760      1.1       agc 			*sp++ = '\0';
    761      1.1       agc 			if (sscanf(sp, "%d", &val) != 1)
    762      1.1       agc 				return 0;
    763      1.1       agc 			if (val < 0 || val > 0xffff)
    764      1.1       agc 				return 0;
    765      1.1       agc 			portal->port = (uint16_t) val;
    766      1.1       agc 		}
    767      1.1       agc 		/* is there a group tag? */
    768      1.1       agc 		for (; isdigit((unsigned char)*sp); sp++) {
    769      1.1       agc 		}
    770      1.1       agc 		if (*sp && *sp != ',')
    771      1.1       agc 			return 0;
    772      1.1       agc 	} else
    773      1.1       agc 		for (sp = str + 1; *sp && *sp != ','; sp++);
    774      1.1       agc 
    775      1.1       agc 	if (*sp) {
    776      1.1       agc 		if (sscanf(sp + 1, "%d", &val) != 1)
    777      1.1       agc 			return 0;
    778      1.1       agc 		if (val < 0 || val > 0xffff)
    779      1.1       agc 			return 0;
    780      1.1       agc 		portal->group_tag = (uint16_t) val;
    781      1.1       agc 		/* truncate source, that's the address */
    782      1.1       agc 		*sp = '\0';
    783      1.1       agc 	}
    784      1.1       agc 	/* only check length, don't verify correct format (too many
    785      1.1       agc 	 * possibilities) */
    786      1.1       agc 	if (strlen(str) >= sizeof(portal->address))
    787      1.1       agc 		return 0;
    788      1.1       agc 
    789      1.1       agc 	strlcpy((char *)portal->address, str, sizeof(portal->address));
    790      1.1       agc 
    791      1.1       agc 	return 1;
    792      1.1       agc }
    793      1.1       agc 
    794      1.1       agc /*
    795      1.1       agc  * refresh_send_target:
    796      1.1       agc  *    Handle REFRESH_TARGETS request for a Send Target
    797      1.1       agc  *
    798      1.1       agc  *    Parameter:
    799      1.1       agc  *          id    The send target ID.
    800      1.1       agc  *
    801      1.1       agc  *    Returns:     status
    802      1.1       agc  */
    803      1.1       agc 
    804      1.1       agc 
    805      1.3       agc static uint32_t
    806      1.1       agc refresh_send_target(uint32_t id)
    807      1.1       agc {
    808      1.1       agc 	uint8_t *response_buffer = NULL;
    809      1.1       agc 	uint32_t response_size;
    810      1.1       agc 	uint32_t ret;
    811      1.1       agc 	uint8_t *TargetName;
    812      1.1       agc 	iscsi_portal_address_t addr;
    813      1.1       agc 	uint8_t *tp, *sp;
    814      1.1       agc 	generic_entry_t *curr;
    815      1.1       agc 	generic_entry_t *next;
    816      1.1       agc 	send_target_t *sendtarg;
    817      1.1       agc 	int rc;
    818      1.1       agc 
    819      1.1       agc 	/*
    820      1.1       agc 	 * Go through our list of portals and mark each one
    821      1.1       agc 	 * belonging to the current sendtargets group to refreshing
    822      1.1       agc 	 * This mark is used afterwards to remove any portals that
    823      1.1       agc 	 * were not refreshed (because the mark gets reset for portals
    824      1.1       agc 	 * that are refreshed).
    825      1.1       agc 	 */
    826      1.1       agc 
    827      1.1       agc 	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
    828      1.2  christos 		portal_t *p = (void *)curr;
    829      1.2  christos 		if (p->portaltype == PORTAL_TYPE_SENDTARGET &&
    830      1.2  christos 		    p->discoveryid == id) {
    831      1.2  christos 			p->portaltype = PORTAL_TYPE_REFRESHING;
    832      1.1       agc 		}
    833      1.1       agc 	}
    834      1.1       agc 
    835      1.1       agc 	if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) {
    836      1.1       agc 		/*
    837      1.1       agc 		 * Parse the response target list
    838      1.1       agc 		 * The SendTargets response in response_buffer is a list of
    839      1.1       agc 		 * target strings. Each target string consists of a TargetName
    840      1.1       agc 		 * string, followed by 0 or more TargetAddress strings:
    841      1.1       agc 		 *
    842      1.1       agc 		 *      TargetName=<target-name>
    843      1.1       agc 		 *      TargetAddress=<hostname-or-ip>[:<tcp-port>],
    844      1.1       agc 		 *				<portal-group-tag>
    845      1.1       agc 		 * The entire list is terminated by a null (after
    846      1.1       agc 		 * response_size bytes) (this terminating NULL was placed
    847      1.1       agc 		 * there by send_targets routine.)
    848      1.1       agc 		 */
    849      1.1       agc 
    850      1.1       agc 		tp = response_buffer;
    851      1.1       agc 		while (*tp) {
    852      1.1       agc 			if (strncmp((char *)tp, "TargetName=", 11) != 0) {
    853      1.1       agc 				DEBOUT(("Response not TargetName <%s>\n", tp));
    854      1.1       agc 				break;
    855      1.1       agc 			}
    856      1.1       agc 			tp += 11;
    857      1.1       agc 			TargetName = tp; /*Point to target name */
    858      1.1       agc 			while (*tp++) {
    859      1.1       agc 			}
    860      1.1       agc 			rc = -1; /* Mark no address found yet */
    861      1.1       agc 
    862      1.1       agc 			/*Now process any "TargetAddress" entries following */
    863      1.1       agc 			while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) {
    864      1.1       agc 				tp += 14;
    865      1.1       agc 				sp = tp; /* save start of address */
    866      1.1       agc 				while (*tp++) {
    867      1.1       agc 				}
    868      1.1       agc 				/*Get the target address */
    869      1.1       agc 				rc = cl_get_address(&addr, (char *)sp);
    870      1.1       agc 				if (rc) {
    871      1.1       agc 					add_discovered_target(TargetName,
    872      1.1       agc 						&addr, PORTAL_TYPE_SENDTARGET,
    873      1.1       agc 						id);
    874      1.1       agc 				} else {
    875  1.4.2.1       tls 					DEBOUT(("Syntax error in returned target address <%s>\n", sp));
    876      1.1       agc 					break;
    877      1.1       agc 				}
    878      1.1       agc 			}
    879      1.1       agc 
    880      1.1       agc 			if (rc == -1) {
    881      1.1       agc 				/* There are no TargetAddress entries
    882      1.1       agc 				 * associated with TargetName. This means the
    883      1.1       agc 				 * sendtarget address is used. */
    884      1.1       agc 				sendtarg = find_send_target_id(id);
    885      1.1       agc 				if (sendtarg != NULL) {
    886      1.1       agc 					add_discovered_target(TargetName,
    887      1.1       agc 						&sendtarg->addr,
    888      1.1       agc 						PORTAL_TYPE_SENDTARGET, id);
    889      1.1       agc 				}
    890      1.1       agc 			}
    891      1.1       agc 		} /* end of while */
    892      1.1       agc 	}
    893      1.1       agc 	/*
    894      1.1       agc 	 * Go through our list of portals and look for ones
    895      1.1       agc 	 * that are still marked for refreshing.
    896      1.1       agc 	 * These are ones that are no longer there and should be removed.
    897      1.1       agc 	 */
    898      1.1       agc 
    899      1.1       agc 	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
    900      1.1       agc 		 curr = next) {
    901      1.2  christos 		portal_t *p = (void *)curr;
    902      1.1       agc 		next = TAILQ_NEXT(curr, link);
    903      1.2  christos 		if (p->portaltype == PORTAL_TYPE_REFRESHING)
    904      1.2  christos 			delete_portal(p, TRUE);
    905      1.1       agc 	}
    906      1.1       agc 
    907      1.1       agc 	/*
    908      1.1       agc 	 * Clean up
    909      1.1       agc 	 */
    910      1.1       agc 
    911      1.1       agc 	if (response_buffer != NULL)
    912      1.1       agc 		free(response_buffer);
    913      1.1       agc 
    914      1.1       agc 	return ret;
    915      1.1       agc }
    916      1.1       agc 
    917      1.1       agc 
    918      1.1       agc /*
    919      1.1       agc  * cleanup_send_target_orphans:
    920      1.1       agc  *    Delete portals that were discovered through a now deleted send target.
    921      1.1       agc  */
    922      1.1       agc 
    923      1.1       agc 
    924      1.3       agc static void
    925      1.1       agc cleanup_orphans(iscsi_portal_types_t type)
    926      1.1       agc {
    927      1.1       agc 	generic_entry_t *curr;
    928      1.1       agc 	generic_entry_t *next;
    929      1.1       agc 
    930      1.1       agc 	/*
    931      1.1       agc 	 * Go through the list of portals and look for ones marked with a zero
    932      1.1       agc 	 * discovery ID, those are associated with send targets that no
    933      1.1       agc 	 * longer exist.
    934      1.1       agc 	 */
    935      1.1       agc 
    936      1.1       agc 	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
    937      1.1       agc 		 curr = next) {
    938      1.2  christos 		portal_t *p = (void *)curr;
    939      1.1       agc 		next = TAILQ_NEXT(curr, link);
    940      1.2  christos 		if (p->portaltype == type && p->discoveryid == 0) {
    941      1.2  christos 			delete_portal(p, TRUE);
    942      1.1       agc 		}
    943      1.1       agc 	}
    944      1.1       agc }
    945      1.1       agc 
    946      1.1       agc 
    947      1.1       agc /*
    948      1.1       agc  * refresh_targets:
    949      1.1       agc  *    Handle REFRESH_TARGETS request:
    950      1.1       agc  *    Refreshes the list of targets discovered via SendTargets or iSNS
    951      1.1       agc  *
    952      1.1       agc  *    Parameter:
    953      1.1       agc  *          The request parameter = iscsid_refresh_targets_req_t containing:
    954      1.1       agc  *             iscsid_list_kind_t   kind;       Kind:
    955      1.1       agc  *                                                  SEND_TARGETS_LIST
    956      1.1       agc  *                                                  ISNS_LIST
    957      1.1       agc  *             uint32_t                num_ids;    # of targets in list
    958      1.1       agc  *             uint32_t            id [1];     List of targets
    959      1.1       agc  *
    960      1.1       agc  *    Returns:     status
    961      1.1       agc  */
    962      1.1       agc 
    963      1.1       agc uint32_t
    964      1.1       agc refresh_targets(iscsid_refresh_req_t * par)
    965      1.1       agc {
    966      1.1       agc 	uint32_t t;
    967      1.1       agc 	uint32_t rc, retval;
    968      1.1       agc 	generic_entry_t *curr;
    969      1.1       agc 
    970      1.1       agc 	retval = ISCSID_STATUS_NO_TARGETS_FOUND;
    971      1.1       agc 
    972      1.1       agc 	switch (par->kind) {
    973      1.1       agc 	case TARGET_LIST:
    974      1.1       agc 		/*
    975      1.1       agc 		 * Refreshing for a specific target makes no sense if it's
    976      1.1       agc 		 * static. Maybe implement it for dynamically dicovered
    977      1.1       agc 		 * targets? But then it's best done through the discovering
    978      1.1       agc 		 * instance, or we'll refresh much more than just the given
    979      1.1       agc 		 * target. And refreshing the whole list is iffy as well. So
    980      1.1       agc 		 * refuse this op on the target list for now.
    981      1.1       agc 		 */
    982      1.1       agc 		break;
    983      1.1       agc 
    984      1.1       agc 	case SEND_TARGETS_LIST:
    985      1.1       agc 		DEB(9, ("Refresh Send Targets List - num_ids = %d\n",
    986      1.1       agc 				par->num_ids));
    987      1.1       agc 		if (par->num_ids) {
    988      1.1       agc 			/* Target ids are specified */
    989      1.1       agc 			for (t = 0; t < par->num_ids; t++) {
    990      1.1       agc 				rc = refresh_send_target(par->id[t]);
    991      1.1       agc 				if (rc == 0) {
    992      1.1       agc 					retval = ISCSID_STATUS_SUCCESS;
    993      1.1       agc 				}
    994      1.1       agc 			}
    995      1.1       agc 		} else {
    996      1.1       agc 			cleanup_orphans(PORTAL_TYPE_SENDTARGET);
    997      1.1       agc 
    998      1.1       agc 			/* No target ids specified - refresh all. */
    999      1.1       agc 			TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
   1000      1.1       agc 				if ((rc = refresh_send_target(curr->sid.id)) == 0)
   1001      1.1       agc 					retval = ISCSID_STATUS_SUCCESS;
   1002      1.1       agc 		}
   1003      1.1       agc 		return retval;
   1004      1.1       agc 
   1005      1.1       agc #ifndef ISCSI_MINIMAL
   1006      1.1       agc 	case ISNS_LIST:
   1007      1.1       agc 		DEB(9, ("Refresh iSNS List - num_ids = %d\n", par->num_ids));
   1008      1.1       agc 		if (par->num_ids) {
   1009      1.1       agc 			/*Target ids are specified */
   1010      1.1       agc 			for (t = 0; t < par->num_ids; t++)
   1011      1.1       agc 				if ((rc = refresh_isns_server(par->id[t])) == 0)
   1012      1.1       agc 					retval = ISCSI_STATUS_SUCCESS;
   1013      1.1       agc 		} else {
   1014      1.1       agc 			cleanup_orphans(PORTAL_TYPE_ISNS);
   1015      1.1       agc 
   1016      1.1       agc 			/*No target ids specified - refresh all. */
   1017      1.1       agc 			TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
   1018      1.1       agc 				if ((rc = refresh_isns_server(curr->sid.id)) == 0)
   1019      1.1       agc 					retval = ISCSI_STATUS_SUCCESS;
   1020      1.1       agc 		}
   1021      1.1       agc 		return retval;
   1022      1.1       agc #endif
   1023      1.1       agc 
   1024      1.1       agc 	default:
   1025      1.1       agc 		break;
   1026      1.1       agc 	}
   1027      1.1       agc 
   1028      1.1       agc 	return ISCSID_STATUS_PARAMETER_INVALID;
   1029      1.1       agc }
   1030