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