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