xref: /netbsd-src/sbin/iscsid/iscsid_targets.c (revision cdc507f0d27576e5c4f30629a5cfe9e1f5271dbe)
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 *
create_portal(target_t * target,iscsi_portal_address_t * addr,iscsi_portal_types_t dtype,uint32_t did)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
delete_portal(portal_t * portal,boolean_t delete_empty)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 *
create_target(uint8_t * name)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
delete_target(target_t * target)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 *
create_send_target(uint8_t * name,iscsi_portal_address_t * addr)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
delete_send_target(send_target_t * send_target)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
add_target(iscsid_add_target_req_t * par,iscsid_response_t ** prsp,int * prsp_temp)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 *
add_discovered_target(uint8_t * TargetName,iscsi_portal_address_t * addr,iscsi_portal_types_t dtype,uint32_t did)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
set_target_options(iscsid_get_set_target_options_t * par)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
set_target_auth(iscsid_set_target_authentication_req_t * par)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
get_target_info(iscsid_list_id_t * par,iscsid_response_t ** prsp,int * prsp_temp)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
add_portal(iscsid_add_portal_req_t * par,iscsid_response_t ** prsp,int * prsp_temp)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
get_portal_info(iscsid_list_id_t * par,iscsid_response_t ** prsp,int * prsp_temp)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
remove_target(iscsid_list_id_t * par)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
cl_get_address(iscsi_portal_address_t * portal,char * str)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
refresh_send_target(uint32_t id)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
cleanup_orphans(iscsi_portal_types_t type)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
refresh_targets(iscsid_refresh_req_t * par)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