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