1/*	$NetBSD: iscsid_targets.c,v 1.3 2011/11/20 01:23:57 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 */
37static uint32_t portarget_id = 0;
38
39/* counter for send_targets ID */
40static 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
58static portal_t *
59create_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 %p\n", 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
132void
133delete_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
170static target_t *
171create_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
207static void
208delete_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
242static target_t *
243create_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 *)(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
274static void
275delete_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
311void
312add_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\n",
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\n"));
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
427target_t *
428add_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\n",
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
468uint32_t
469set_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
493uint32_t
494set_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
520void
521get_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\n", 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
581void
582add_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\n",
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)\n", 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
643void
644get_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\n", 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
694uint32_t
695remove_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\n", 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
739static int
740cl_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
805static uint32_t
806refresh_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>\n", 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>\n",
876							tp));
877					break;
878				}
879			}
880
881			if (rc == -1) {
882				/* There are no TargetAddress entries
883				 * associated with TargetName. This means the
884				 * sendtarget address is used. */
885				sendtarg = find_send_target_id(id);
886				if (sendtarg != NULL) {
887					add_discovered_target(TargetName,
888						&sendtarg->addr,
889						PORTAL_TYPE_SENDTARGET, id);
890				}
891			}
892		} /* end of while */
893	}
894	/*
895	 * Go through our list of portals and look for ones
896	 * that are still marked for refreshing.
897	 * These are ones that are no longer there and should be removed.
898	 */
899
900	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
901		 curr = next) {
902		portal_t *p = (void *)curr;
903		next = TAILQ_NEXT(curr, link);
904		if (p->portaltype == PORTAL_TYPE_REFRESHING)
905			delete_portal(p, TRUE);
906	}
907
908	/*
909	 * Clean up
910	 */
911
912	if (response_buffer != NULL)
913		free(response_buffer);
914
915	return ret;
916}
917
918
919/*
920 * cleanup_send_target_orphans:
921 *    Delete portals that were discovered through a now deleted send target.
922 */
923
924
925static void
926cleanup_orphans(iscsi_portal_types_t type)
927{
928	generic_entry_t *curr;
929	generic_entry_t *next;
930
931	/*
932	 * Go through the list of portals and look for ones marked with a zero
933	 * discovery ID, those are associated with send targets that no
934	 * longer exist.
935	 */
936
937	for (curr = TAILQ_FIRST(&list[PORTAL_LIST].list); curr != NULL;
938		 curr = next) {
939		portal_t *p = (void *)curr;
940		next = TAILQ_NEXT(curr, link);
941		if (p->portaltype == type && p->discoveryid == 0) {
942			delete_portal(p, TRUE);
943		}
944	}
945}
946
947
948/*
949 * refresh_targets:
950 *    Handle REFRESH_TARGETS request:
951 *    Refreshes the list of targets discovered via SendTargets or iSNS
952 *
953 *    Parameter:
954 *          The request parameter = iscsid_refresh_targets_req_t containing:
955 *             iscsid_list_kind_t   kind;       Kind:
956 *                                                  SEND_TARGETS_LIST
957 *                                                  ISNS_LIST
958 *             uint32_t                num_ids;    # of targets in list
959 *             uint32_t            id [1];     List of targets
960 *
961 *    Returns:     status
962 */
963
964uint32_t
965refresh_targets(iscsid_refresh_req_t * par)
966{
967	uint32_t t;
968	uint32_t rc, retval;
969	generic_entry_t *curr;
970
971	retval = ISCSID_STATUS_NO_TARGETS_FOUND;
972
973	switch (par->kind) {
974	case TARGET_LIST:
975		/*
976		 * Refreshing for a specific target makes no sense if it's
977		 * static. Maybe implement it for dynamically dicovered
978		 * targets? But then it's best done through the discovering
979		 * instance, or we'll refresh much more than just the given
980		 * target. And refreshing the whole list is iffy as well. So
981		 * refuse this op on the target list for now.
982		 */
983		break;
984
985	case SEND_TARGETS_LIST:
986		DEB(9, ("Refresh Send Targets List - num_ids = %d\n",
987				par->num_ids));
988		if (par->num_ids) {
989			/* Target ids are specified */
990			for (t = 0; t < par->num_ids; t++) {
991				rc = refresh_send_target(par->id[t]);
992				if (rc == 0) {
993					retval = ISCSID_STATUS_SUCCESS;
994				}
995			}
996		} else {
997			cleanup_orphans(PORTAL_TYPE_SENDTARGET);
998
999			/* No target ids specified - refresh all. */
1000			TAILQ_FOREACH(curr, &list[SEND_TARGETS_LIST].list, link)
1001				if ((rc = refresh_send_target(curr->sid.id)) == 0)
1002					retval = ISCSID_STATUS_SUCCESS;
1003		}
1004		return retval;
1005
1006#ifndef ISCSI_MINIMAL
1007	case ISNS_LIST:
1008		DEB(9, ("Refresh iSNS List - num_ids = %d\n", par->num_ids));
1009		if (par->num_ids) {
1010			/*Target ids are specified */
1011			for (t = 0; t < par->num_ids; t++)
1012				if ((rc = refresh_isns_server(par->id[t])) == 0)
1013					retval = ISCSI_STATUS_SUCCESS;
1014		} else {
1015			cleanup_orphans(PORTAL_TYPE_ISNS);
1016
1017			/*No target ids specified - refresh all. */
1018			TAILQ_FOREACH(curr, &list[ISNS_LIST].list, link)
1019				if ((rc = refresh_isns_server(curr->sid.id)) == 0)
1020					retval = ISCSI_STATUS_SUCCESS;
1021		}
1022		return retval;
1023#endif
1024
1025	default:
1026		break;
1027	}
1028
1029	return ISCSID_STATUS_PARAMETER_INVALID;
1030}
1031