Home | History | Annotate | Line # | Download | only in iscsid
iscsid_targets.c revision 1.1
      1 /*	$NetBSD: iscsid_targets.c,v 1.1 2011/10/23 21:11:23 agc 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\n",
     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!\n"));
     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!\n"));
    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 %x\n", (int) 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\n", name));
    176 
    177 	if ((target = calloc(1, sizeof(*target))) == NULL) {
    178 		DEBOUT(("Out of memory in create_target!\n"));
    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\n", 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 *) 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 		if (((portal_t *) curr)->portaltype == PORTAL_TYPE_SENDTARGET &&
    284 			((portal_t *) curr)->discoveryid == id)
    285 			((portal_t *) curr)->discoveryid = 0; /* mark deleted */
    286 	}
    287 
    288 	TAILQ_REMOVE(&list[SEND_TARGETS_LIST].list, &send_target->entry, link);
    289 	list[SEND_TARGETS_LIST].num_entries--;
    290 	free(send_target);
    291 }
    292 
    293 
    294 
    295 /*
    296  * add_target:
    297  *    Handle ADD_TARGET request: Create a target or send_target and its
    298  *    associated portals.
    299  *    This routine allows the same target to be defined more than once,
    300  *    adding any missing data (for example additional portals).
    301  *
    302  *    Parameter:
    303  *          par         The request parameters.
    304  *          prsp        Pointer to address of response buffer.
    305  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    306  *                      for static buffer.
    307  */
    308 
    309 
    310 void
    311 add_target(iscsid_add_target_req_t *par, iscsid_response_t **prsp,
    312 			int *prsp_temp)
    313 {
    314 	iscsid_add_target_rsp_t *res;
    315 	iscsid_response_t *rsp = *prsp;
    316 	target_t *target, *tn;
    317 	portal_t *portal;
    318 	int i, num;
    319 
    320 	DEB(9, ("Add Target, name %s, num_portals %d\n",
    321 			par->TargetName, par->num_portals));
    322 
    323 	if (par->list_kind == SEND_TARGETS_LIST && par->num_portals != 1) {
    324 		rsp->status = ISCSID_STATUS_PARAMETER_INVALID;
    325 		return;
    326 	}
    327 	/* check to see if the target already exists */
    328 	if ((par->TargetName[0] &&
    329 	     (target = find_TargetName(par->list_kind, par->TargetName)) != NULL) ||
    330 	    (par->list_kind == SEND_TARGETS_LIST &&
    331 	     (target = (target_t *)
    332 			find_send_target_by_addr(&par->portal[0])) != NULL)) {
    333 		num = target->num_portals;
    334 
    335 		/* symbolic name? */
    336 		if (par->sym_name[0]) {
    337 			/* already named? rename if OK */
    338 			tn = find_target_symname(par->list_kind, par->sym_name);
    339 			if (tn && tn != target) {
    340 				rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    341 				return;
    342 			}
    343 			strlcpy((char *)target->entry.sid.name, (char *)par->sym_name, sizeof(target->entry.sid.name));
    344 		}
    345 	} else {
    346 		if (par->sym_name[0] &&
    347 			(find_target_symname(par->list_kind, par->sym_name) ||
    348 			 find_portal_name(par->sym_name))) {
    349 			rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    350 			return;
    351 		}
    352 
    353 		if (par->list_kind == SEND_TARGETS_LIST)
    354 			target = create_send_target(par->TargetName, &par->portal[0]);
    355 		else
    356 			target = create_target(par->TargetName);
    357 
    358 		if (target == NULL) {
    359 			rsp->status = ISCSID_STATUS_NO_RESOURCES;
    360 			return;
    361 		}
    362 		num = 0;
    363 		strlcpy((char *)target->entry.sid.name, (char *)par->sym_name,
    364 			sizeof(target->entry.sid.name));
    365 	}
    366 
    367 	rsp = make_rsp(sizeof(*res) + (par->num_portals * sizeof(uint32_t)),
    368 			prsp, prsp_temp);
    369 	if (rsp == NULL)
    370 		return;
    371 
    372 	res = (iscsid_add_target_rsp_t *) rsp->parameter;
    373 	res->target_id = target->entry.sid.id;
    374 
    375 	/* link into target list */
    376 	if (!num) {
    377 		TAILQ_INSERT_TAIL(&list[par->list_kind].list, &target->entry,
    378 			link);
    379 		list[par->list_kind].num_entries++;
    380 	}
    381 
    382 	/*
    383 	   Add the given portals. Note that create_portal also checks for
    384 	   duplicate entries, and returns the pointer to the existing entry
    385 	   if the request is a duplicate.
    386 	 */
    387 
    388 	if (par->list_kind == SEND_TARGETS_LIST) {
    389 		res->portal_id[0] = target->entry.sid.id;
    390 		res->num_portals = 1;
    391 	} else {
    392 		for (i = 0; i < (int)par->num_portals; i++) {
    393 			portal = create_portal(target, &par->portal[i],
    394 					PORTAL_TYPE_STATIC,
    395 					target->entry.sid.id);
    396 			if (portal == NULL) {
    397 				rsp->status = ISCSID_STATUS_NO_RESOURCES;
    398 				break;
    399 			}
    400 			res->portal_id[i] = portal->entry.sid.id;
    401 		}
    402 		res->num_portals = i;
    403 	}
    404 
    405 	DEB(9, ("AddTarget returns\n"));
    406 }
    407 
    408 
    409 /*
    410  * add_discovered_target:
    411  *    Check whether the given target and portal already exist.
    412  *    If not, add them.
    413  *
    414  *    Parameter:
    415  *          TargetName
    416  *          portal
    417  *          dtype = type of portal added: PORTAL_TYPE_SENDTARGET or
    418  *					PORTAL_TYPE_ISNS
    419  *          did = ID of SendTargets or iSNS for which portal was discovered
    420  *
    421  *    Returns: Pointer to created target, NULL on error (out of memory)
    422  *    Always sets portaltype to dtype even if portal already exists
    423  *      (used for refreshing to mark portals that we find)
    424  */
    425 
    426 target_t *
    427 add_discovered_target(uint8_t * TargetName, iscsi_portal_address_t * addr,
    428 				iscsi_portal_types_t dtype, uint32_t did)
    429 {
    430 	target_t *target;
    431 	portal_t *portal;
    432 
    433 	DEB(9, ("Add Discovered Target, name %s, addr %s\n",
    434 			TargetName, addr->address));
    435 
    436 	if ((target = find_TargetName(TARGET_LIST, TargetName)) == NULL) {
    437 		if ((target = create_target(TargetName)) == NULL) {
    438 			return NULL;
    439 		}
    440 		portal = create_portal(target, addr, dtype, did);
    441 		if (portal == NULL) {
    442 			free(target);
    443 			return NULL;
    444 		}
    445 		TAILQ_INSERT_TAIL(&list[TARGET_LIST].list, &target->entry, link);
    446 		list[TARGET_LIST].num_entries++;
    447 	} else if ((portal = create_portal(target, addr, dtype, did)) == NULL) {
    448 		return NULL;
    449 	}
    450 	portal->portaltype = dtype;
    451 
    452 	return target;
    453 }
    454 
    455 
    456 /*
    457  * set_target_options:
    458  *    Handle SET_TARGET_OPTIONS request: Copy the given options into the
    459  *    target structure.
    460  *
    461  *    Parameter:
    462  *          par         The request parameters.
    463  *
    464  *    Returns:     status
    465  */
    466 
    467 uint32_t
    468 set_target_options(iscsid_get_set_target_options_t * par)
    469 {
    470 	target_t *target;
    471 
    472 	if ((target = find_target(par->list_kind, &par->target_id)) == NULL)
    473 		return ISCSID_STATUS_INVALID_TARGET_ID;
    474 
    475 	target->options = *par;
    476 
    477 	return ISCSID_STATUS_SUCCESS;
    478 }
    479 
    480 
    481 /*
    482  * set_target_auth:
    483  *    Handle SET_TARGET_AUTHENTICATION request: Copy the given options into the
    484  *    target structure.
    485  *
    486  *    Parameter:
    487  *          par         The request parameters.
    488  *
    489  *    Returns:     status
    490  */
    491 
    492 uint32_t
    493 set_target_auth(iscsid_set_target_authentication_req_t * par)
    494 {
    495 	target_t *target;
    496 
    497 	if ((target = find_target(par->list_kind, &par->target_id)) == NULL) {
    498 		return ISCSID_STATUS_INVALID_TARGET_ID;
    499 	}
    500 	target->auth = *par;
    501 
    502 	return ISCSID_STATUS_SUCCESS;
    503 }
    504 
    505 
    506 /*
    507  * get_target_info:
    508  *    Handle GET_TARGET_INFO request: Return information about the given
    509  *    target and its portals. If a portal ID is given, returns only the
    510  *    target info and the ID of this portal.
    511  *
    512  *    Parameter:
    513  *          par         The request parameters.
    514  *          prsp        Pointer to address of response buffer.
    515  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    516  *                      for static buffer.
    517  */
    518 
    519 void
    520 get_target_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
    521 {
    522 	iscsid_get_target_rsp_t *res;
    523 	iscsid_response_t *rsp = *prsp;
    524 	uint32_t *idp;
    525 	target_t *target;
    526 	portal_group_t *cgroup;
    527 	portal_t *curr = NULL;
    528 	int num = 1;
    529 
    530 	DEB(10, ("get_target_info, id %d\n", par->id.id));
    531 
    532 	if ((target = find_target(par->list_kind, &par->id)) == NULL) {
    533 		if (par->list_kind == SEND_TARGETS_LIST ||
    534 		    (curr = find_portal(&par->id)) == NULL) {
    535 			rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
    536 			return;
    537 		}
    538 		target = curr->target;
    539 	} else if (par->list_kind != SEND_TARGETS_LIST) {
    540 		num = target->num_portals;
    541 	}
    542 	rsp = make_rsp(sizeof(*res) + (num - 1) * sizeof(uint32_t),
    543 			prsp, prsp_temp);
    544 	if (rsp == NULL)
    545 		return;
    546 
    547 	res = (iscsid_get_target_rsp_t *) rsp->parameter;
    548 	res->target_id = target->entry.sid;
    549 	strlcpy((char *)res->TargetName, (char *)target->TargetName,
    550 			sizeof(res->TargetName));
    551 	strlcpy((char *)res->TargetAlias, (char *)target->TargetAlias,
    552 			sizeof(res->TargetAlias));
    553 
    554 	res->num_portals = num;
    555 	idp = res->portal;
    556 
    557 	if (curr) {
    558 		*idp = curr->entry.sid.id;
    559 	} else if (par->list_kind != SEND_TARGETS_LIST) {
    560 		TAILQ_FOREACH(cgroup, &target->group_list, groups)
    561 			TAILQ_FOREACH(curr, &cgroup->portals, group_list)
    562 			* idp++ = curr->entry.sid.id;
    563 	} else
    564 		*idp = target->entry.sid.id;
    565 }
    566 
    567 
    568 /*
    569  * add_portal:
    570  *    Handle ADD_PORTAL request: Add a portal to an existing target.
    571  *
    572  *    Parameter:
    573  *          par         The request parameters.
    574  *          prsp        Pointer to address of response buffer.
    575  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    576  *                      for static buffer.
    577  */
    578 
    579 
    580 void
    581 add_portal(iscsid_add_portal_req_t *par, iscsid_response_t **prsp,
    582 			int *prsp_temp)
    583 {
    584 	iscsid_add_portal_rsp_t *res;
    585 	iscsid_response_t *rsp = *prsp;
    586 	target_t *target;
    587 	portal_t *portal;
    588 
    589 	DEB(9, ("Add portal: target %d (%s), symname %s, addr %s\n",
    590 			par->target_id.id, par->target_id.name,
    591 			par->sym_name, par->portal.address));
    592 
    593 	if ((target = find_target(TARGET_LIST, &par->target_id)) == NULL) {
    594 		rsp->status = ISCSID_STATUS_INVALID_TARGET_ID;
    595 		return;
    596 	}
    597 
    598 	if (par->sym_name[0] &&
    599 		(find_target_symname(TARGET_LIST, par->sym_name) ||
    600 		 find_portal_name(par->sym_name))) {
    601 		rsp->status = ISCSID_STATUS_DUPLICATE_NAME;
    602 		return;
    603 	}
    604 
    605 	portal = create_portal(target, &par->portal, PORTAL_TYPE_STATIC,
    606 							target->entry.sid.id);
    607 	if (portal == NULL) {
    608 		rsp->status = ISCSID_STATUS_NO_RESOURCES;
    609 		return;
    610 	}
    611 
    612 	if (par->sym_name[0]) {
    613 		strlcpy((char *)portal->entry.sid.name, (char *)par->sym_name,
    614 			sizeof(portal->entry.sid.name));
    615 	}
    616 	portal->options = par->options;
    617 
    618 	rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
    619 	if (rsp == NULL)
    620 		return;
    621 
    622 	res = (iscsid_add_portal_rsp_t *) rsp->parameter;
    623 	res->target_id = target->entry.sid;
    624 	res->portal_id = portal->entry.sid;
    625 
    626 	DEB(9, ("AddPortal success (id %d)\n", portal->entry.sid.id));
    627 }
    628 
    629 
    630 /*
    631  * get_portal_info:
    632  *    Handle GET_PORTAL_INFO request: Return information about the given
    633  *    portal.
    634  *
    635  *    Parameter:
    636  *          par         The request parameters.
    637  *          prsp        Pointer to address of response buffer.
    638  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
    639  *                      for static buffer.
    640  */
    641 
    642 void
    643 get_portal_info(iscsid_list_id_t *par, iscsid_response_t **prsp, int *prsp_temp)
    644 {
    645 	iscsid_get_portal_rsp_t *res;
    646 	iscsid_response_t *rsp = *prsp;
    647 	portal_t *portal = NULL;
    648 	send_target_t *starg = NULL;
    649 	int err;
    650 
    651 	DEB(10, ("get_portal_info, id %d\n", par->id.id));
    652 
    653 	if (par->list_kind == SEND_TARGETS_LIST)
    654 		err = ((starg = (send_target_t *) find_target(par->list_kind,
    655 							&par->id)) == NULL);
    656 	else
    657 		err = ((portal = find_portal(&par->id)) == NULL);
    658 
    659 	if (err) {
    660 		rsp->status = ISCSID_STATUS_INVALID_PORTAL_ID;
    661 		return;
    662 	}
    663 
    664 	rsp = make_rsp(sizeof(*res), prsp, prsp_temp);
    665 	if (rsp == NULL)
    666 		return;
    667 
    668 	res = (iscsid_get_portal_rsp_t *) rsp->parameter;
    669 	if (par->list_kind == SEND_TARGETS_LIST) {
    670 		res->target_id = starg->entry.sid;
    671 		res->portal_id = starg->entry.sid;
    672 		res->portal = starg->addr;
    673 	} else {
    674 		res->target_id = portal->target->entry.sid;
    675 		res->portal_id = portal->entry.sid;
    676 		res->portal = portal->addr;
    677 	}
    678 }
    679 
    680 /*
    681  * remove_target:
    682  *    Handle REMOVE_TARGET request: Removes a target, target portal,
    683  *		or Send-Targets portal from its respective list.
    684  *      Removing a target will remove all associated portals.
    685  *
    686  *    Parameter:
    687  *          par         The request parameters = iscsid_list_id_t
    688  *						containing the target ID.
    689  *
    690  *    Returns:     status
    691  */
    692 
    693 uint32_t
    694 remove_target(iscsid_list_id_t * par)
    695 {
    696 	target_t *target = NULL;
    697 	portal_t *portal = NULL;
    698 	send_target_t *starg = NULL;
    699 	int err;
    700 
    701 	DEB(9, ("remove_target, id %d\n", par->id.id));
    702 
    703 	if (par->list_kind == SEND_TARGETS_LIST) {
    704 		err = ((starg = (send_target_t *) find_target(par->list_kind,
    705 							&par->id)) == NULL);
    706 		if (!err) {
    707 			delete_send_target(starg);
    708 		}
    709 	} else if (par->list_kind == PORTAL_LIST) {
    710 		err = ((portal = find_portal(&par->id)) == NULL);
    711 		if (!err) {
    712 			delete_portal(portal, FALSE);
    713 		}
    714 	} else {
    715 		target = find_target(par->list_kind, &par->id);
    716 		err = (target == NULL);
    717 		if (!err) {
    718 			delete_target(target);
    719 		}
    720 	}
    721 
    722 	return err ? ISCSID_STATUS_INVALID_PORTAL_ID : ISCSID_STATUS_SUCCESS;
    723 }
    724 
    725 
    726 
    727 /*
    728  * cl_get_address:
    729  *    Get an address specification that may include port and group tag.
    730  *
    731  *    Parameter:
    732  *          portal   The portal address
    733  *          str      The parameter string to scan
    734  *
    735  *    Returns:    0 on error, 1 if OK.
    736  */
    737 
    738 STATIC int
    739 cl_get_address(iscsi_portal_address_t * portal, char *str)
    740 {
    741 	char *sp, *sp2;
    742 	int val;
    743 
    744 	/* is there a port? don't check inside square brackets (IPv6 addr) */
    745 	for (sp = str + 1, val = 0; *sp && (*sp != ':' || val); sp++) {
    746 		if (*sp == '[')
    747 			val = 1;
    748 		else if (*sp == ']')
    749 			val = 0;
    750 	}
    751 
    752 	/* */
    753 	if (*sp) {
    754 		for (sp2 = sp + 1; *sp2 && *sp2 != ':'; sp2++);
    755 		/* if there's a second colon, assume it's an unbracketed IPv6
    756 		 * address */
    757 		if (!*sp2) {
    758 			/* truncate source, that's the address */
    759 			*sp++ = '\0';
    760 			if (sscanf(sp, "%d", &val) != 1)
    761 				return 0;
    762 			if (val < 0 || val > 0xffff)
    763 				return 0;
    764 			portal->port = (uint16_t) val;
    765 		}
    766 		/* is there a group tag? */
    767 		for (; isdigit((unsigned char)*sp); sp++) {
    768 		}
    769 		if (*sp && *sp != ',')
    770 			return 0;
    771 	} else
    772 		for (sp = str + 1; *sp && *sp != ','; sp++);
    773 
    774 	if (*sp) {
    775 		if (sscanf(sp + 1, "%d", &val) != 1)
    776 			return 0;
    777 		if (val < 0 || val > 0xffff)
    778 			return 0;
    779 		portal->group_tag = (uint16_t) val;
    780 		/* truncate source, that's the address */
    781 		*sp = '\0';
    782 	}
    783 	/* only check length, don't verify correct format (too many
    784 	 * possibilities) */
    785 	if (strlen(str) >= sizeof(portal->address))
    786 		return 0;
    787 
    788 	strlcpy((char *)portal->address, str, sizeof(portal->address));
    789 
    790 	return 1;
    791 }
    792 
    793 /*
    794  * refresh_send_target:
    795  *    Handle REFRESH_TARGETS request for a Send Target
    796  *
    797  *    Parameter:
    798  *          id    The send target ID.
    799  *
    800  *    Returns:     status
    801  */
    802 
    803 
    804 STATIC uint32_t
    805 refresh_send_target(uint32_t id)
    806 {
    807 	uint8_t *response_buffer = NULL;
    808 	uint32_t response_size;
    809 	uint32_t ret;
    810 	uint8_t *TargetName;
    811 	iscsi_portal_address_t addr;
    812 	uint8_t *tp, *sp;
    813 	generic_entry_t *curr;
    814 	generic_entry_t *next;
    815 	send_target_t *sendtarg;
    816 	int rc;
    817 
    818 	/*
    819 	 * Go through our list of portals and mark each one
    820 	 * belonging to the current sendtargets group to refreshing
    821 	 * This mark is used afterwards to remove any portals that
    822 	 * were not refreshed (because the mark gets reset for portals
    823 	 * that are refreshed).
    824 	 */
    825 
    826 	TAILQ_FOREACH(curr, &list[PORTAL_LIST].list, link) {
    827 		if (((portal_t *) curr)->portaltype == PORTAL_TYPE_SENDTARGET &&
    828 		    ((portal_t *) curr)->discoveryid == id) {
    829 			((portal_t *)curr)->portaltype = PORTAL_TYPE_REFRESHING;
    830 		}
    831 	}
    832 
    833 	if ((ret = send_targets(id, &response_buffer, &response_size)) == 0) {
    834 		/*
    835 		 * Parse the response target list
    836 		 * The SendTargets response in response_buffer is a list of
    837 		 * target strings. Each target string consists of a TargetName
    838 		 * string, followed by 0 or more TargetAddress strings:
    839 		 *
    840 		 *      TargetName=<target-name>
    841 		 *      TargetAddress=<hostname-or-ip>[:<tcp-port>],
    842 		 *				<portal-group-tag>
    843 		 * The entire list is terminated by a null (after
    844 		 * response_size bytes) (this terminating NULL was placed
    845 		 * there by send_targets routine.)
    846 		 */
    847 
    848 		tp = response_buffer;
    849 		while (*tp) {
    850 			if (strncmp((char *)tp, "TargetName=", 11) != 0) {
    851 				DEBOUT(("Response not TargetName <%s>\n", tp));
    852 				break;
    853 			}
    854 			tp += 11;
    855 			TargetName = tp; /*Point to target name */
    856 			while (*tp++) {
    857 			}
    858 			rc = -1; /* Mark no address found yet */
    859 
    860 			/*Now process any "TargetAddress" entries following */
    861 			while (*tp && strncmp((char *)tp, "TargetAddress=", 14) == 0) {
    862 				tp += 14;
    863 				sp = tp; /* save start of address */
    864 				while (*tp++) {
    865 				}
    866 				/*Get the target address */
    867 				rc = cl_get_address(&addr, (char *)sp);
    868 				if (rc) {
    869 					add_discovered_target(TargetName,
    870 						&addr, PORTAL_TYPE_SENDTARGET,
    871 						id);
    872 				} else {
    873 					DEBOUT(("Syntax error in returned target address <%s>\n",
    874 							tp));
    875 					break;
    876 				}
    877 			}
    878 
    879 			if (rc == -1) {
    880 				/* There are no TargetAddress entries
    881 				 * associated with TargetName. This means the
    882 				 * sendtarget address is used. */
    883 				sendtarg = find_send_target_id(id);
    884 				if (sendtarg != NULL) {
    885 					add_discovered_target(TargetName,
    886 						&sendtarg->addr,
    887 						PORTAL_TYPE_SENDTARGET, id);
    888 				}
    889 			}
    890 		} /* end of while */
    891 	}
    892 	/*
    893 	 * Go through our list of portals and look for ones
    894 	 * that are still marked for refreshing.
    895 	 * These are ones that are no longer there and should be removed.
    896 	 */
    897 
    898 	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
    899 		 curr = next) {
    900 		next = TAILQ_NEXT(curr, link);
    901 		if (((portal_t *) curr)->portaltype == PORTAL_TYPE_REFRESHING)
    902 			delete_portal((portal_t *) curr, TRUE);
    903 	}
    904 
    905 	/*
    906 	 * Clean up
    907 	 */
    908 
    909 	if (response_buffer != NULL)
    910 		free(response_buffer);
    911 
    912 	return ret;
    913 }
    914 
    915 
    916 /*
    917  * cleanup_send_target_orphans:
    918  *    Delete portals that were discovered through a now deleted send target.
    919  */
    920 
    921 
    922 STATIC void
    923 cleanup_orphans(iscsi_portal_types_t type)
    924 {
    925 	generic_entry_t *curr;
    926 	generic_entry_t *next;
    927 
    928 	/*
    929 	 * Go through the list of portals and look for ones marked with a zero
    930 	 * discovery ID, those are associated with send targets that no
    931 	 * longer exist.
    932 	 */
    933 
    934 	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
    935 		 curr = next) {
    936 		next = TAILQ_NEXT(curr, link);
    937 		if (((portal_t *)curr)->portaltype == type &&
    938 		    ((portal_t *)curr)->discoveryid == 0) {
    939 			delete_portal((portal_t *) curr, TRUE);
    940 		}
    941 	}
    942 }
    943 
    944 
    945 /*
    946  * refresh_targets:
    947  *    Handle REFRESH_TARGETS request:
    948  *    Refreshes the list of targets discovered via SendTargets or iSNS
    949  *
    950  *    Parameter:
    951  *          The request parameter = iscsid_refresh_targets_req_t containing:
    952  *             iscsid_list_kind_t   kind;       Kind:
    953  *                                                  SEND_TARGETS_LIST
    954  *                                                  ISNS_LIST
    955  *             uint32_t                num_ids;    # of targets in list
    956  *             uint32_t            id [1];     List of targets
    957  *
    958  *    Returns:     status
    959  */
    960 
    961 uint32_t
    962 refresh_targets(iscsid_refresh_req_t * par)
    963 {
    964 	uint32_t t;
    965 	uint32_t rc, retval;
    966 	generic_entry_t *curr;
    967 
    968 	retval = ISCSID_STATUS_NO_TARGETS_FOUND;
    969 
    970 	switch (par->kind) {
    971 	case TARGET_LIST:
    972 		/*
    973 		 * Refreshing for a specific target makes no sense if it's
    974 		 * static. Maybe implement it for dynamically dicovered
    975 		 * targets? But then it's best done through the discovering
    976 		 * instance, or we'll refresh much more than just the given
    977 		 * target. And refreshing the whole list is iffy as well. So
    978 		 * refuse this op on the target list for now.
    979 		 */
    980 		break;
    981 
    982 	case SEND_TARGETS_LIST:
    983 		DEB(9, ("Refresh Send Targets List - num_ids = %d\n",
    984 				par->num_ids));
    985 		if (par->num_ids) {
    986 			/* Target ids are specified */
    987 			for (t = 0; t < par->num_ids; t++) {
    988 				rc = refresh_send_target(par->id[t]);
    989 				if (rc == 0) {
    990 					retval = ISCSID_STATUS_SUCCESS;
    991 				}
    992 			}
    993 		} else {
    994 			cleanup_orphans(PORTAL_TYPE_SENDTARGET);
    995 
    996 			/* No target ids specified - refresh all. */
    997 			TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
    998 				if ((rc = refresh_send_target(curr->sid.id)) == 0)
    999 					retval = ISCSID_STATUS_SUCCESS;
   1000 		}
   1001 		return retval;
   1002 
   1003 #ifndef ISCSI_MINIMAL
   1004 	case ISNS_LIST:
   1005 		DEB(9, ("Refresh iSNS List - num_ids = %d\n", par->num_ids));
   1006 		if (par->num_ids) {
   1007 			/*Target ids are specified */
   1008 			for (t = 0; t < par->num_ids; t++)
   1009 				if ((rc = refresh_isns_server(par->id[t])) == 0)
   1010 					retval = ISCSI_STATUS_SUCCESS;
   1011 		} else {
   1012 			cleanup_orphans(PORTAL_TYPE_ISNS);
   1013 
   1014 			/*No target ids specified - refresh all. */
   1015 			TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
   1016 				if ((rc = refresh_isns_server(curr->sid.id)) == 0)
   1017 					retval = ISCSI_STATUS_SUCCESS;
   1018 		}
   1019 		return retval;
   1020 #endif
   1021 
   1022 	default:
   1023 		break;
   1024 	}
   1025 
   1026 	return ISCSID_STATUS_PARAMETER_INVALID;
   1027 }
   1028