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