1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 /* 25 * Copyright (c) 2012, Nexenta Systems, Inc. All rights reserved. 26 */ 27 28 #include <sys/time.h> 29 30 #if defined(_KERNEL) 31 #include <sys/ddi.h> 32 #include <sys/types.h> 33 #include <sys/sunddi.h> 34 #include <sys/socket.h> 35 #include <inet/tcp.h> 36 #include <inet/ip.h> 37 #else 38 #include <stdio.h> 39 #include <strings.h> 40 #include <stdlib.h> 41 #include <errno.h> 42 #include <sys/types.h> 43 #include <sys/socket.h> 44 #include <netinet/in.h> 45 #include <arpa/inet.h> 46 #endif 47 48 #include <sys/iscsit/iscsit_common.h> 49 #include <sys/iscsi_protocol.h> 50 #include <sys/iscsit/isns_protocol.h> 51 52 void * 53 iscsit_zalloc(size_t size) 54 { 55 #if defined(_KERNEL) 56 return (kmem_zalloc(size, KM_SLEEP)); 57 #else 58 return (calloc(1, size)); 59 #endif 60 } 61 62 void 63 iscsit_free(void *buf, size_t size) /* ARGSUSED */ 64 { 65 #if defined(_KERNEL) 66 kmem_free(buf, size); 67 #else 68 free(buf); 69 #endif 70 } 71 72 /* 73 * default_port should be the port to be used, if not specified 74 * as part of the supplied string 'arg'. 75 */ 76 77 #define NI_MAXHOST 1025 78 #define NI_MAXSERV 32 79 80 81 struct sockaddr_storage * 82 it_common_convert_sa(char *arg, struct sockaddr_storage *buf, 83 uint32_t default_port) 84 { 85 /* Why does addrbuf need to be this big!??! XXX */ 86 char addrbuf[NI_MAXHOST + NI_MAXSERV + 1]; 87 char *addr_str; 88 char *port_str; 89 #ifndef _KERNEL 90 char *errchr; 91 #endif 92 long tmp_port = 0; 93 sa_family_t af; 94 95 struct sockaddr_in *sin; 96 struct sockaddr_in6 *sin6; 97 struct sockaddr_storage *sa = buf; 98 99 if (!arg || !buf) { 100 return (NULL); 101 } 102 103 bzero(buf, sizeof (struct sockaddr_storage)); 104 105 /* don't modify the passed-in string */ 106 (void) strlcpy(addrbuf, arg, sizeof (addrbuf)); 107 108 addr_str = addrbuf; 109 110 if (*addr_str == '[') { 111 /* 112 * An IPv6 address must be inside square brackets 113 */ 114 port_str = strchr(addr_str, ']'); 115 if (!port_str) { 116 /* No closing bracket */ 117 return (NULL); 118 } 119 120 /* strip off the square brackets so we can convert */ 121 addr_str++; 122 *port_str = '\0'; 123 port_str++; 124 125 if (*port_str == ':') { 126 /* TCP port to follow */ 127 port_str++; 128 } else if (*port_str == '\0') { 129 /* No port specified */ 130 port_str = NULL; 131 } else { 132 /* malformed */ 133 return (NULL); 134 } 135 af = AF_INET6; 136 } else { 137 port_str = strchr(addr_str, ':'); 138 if (port_str) { 139 *port_str = '\0'; 140 port_str++; 141 } 142 af = AF_INET; 143 } 144 145 if (port_str) { 146 #if defined(_KERNEL) 147 if (ddi_strtol(port_str, NULL, 10, &tmp_port) != 0) { 148 return (NULL); 149 } 150 #else 151 tmp_port = strtol(port_str, &errchr, 10); 152 #endif 153 if (tmp_port < 0 || tmp_port > 65535) { 154 return (NULL); 155 } 156 } else { 157 tmp_port = default_port; 158 } 159 160 sa->ss_family = af; 161 162 sin = (struct sockaddr_in *)sa; 163 if (af == AF_INET) { 164 if (inet_pton(af, addr_str, 165 (void *)&(sin->sin_addr.s_addr)) != 1) { 166 return (NULL); 167 } 168 sin->sin_port = htons(tmp_port); 169 } else { 170 sin6 = (struct sockaddr_in6 *)sa; 171 if (inet_pton(af, addr_str, 172 (void *)&(sin6->sin6_addr.s6_addr)) != 1) { 173 return (NULL); 174 } 175 sin6->sin6_port = htons(tmp_port); 176 } 177 178 /* successful */ 179 return (sa); 180 } 181 182 183 /* Functions to convert iSCSI target structures to/from nvlists. */ 184 185 #ifndef _KERNEL 186 int 187 it_config_to_nv(it_config_t *cfg, nvlist_t **nvl) 188 { 189 int ret; 190 nvlist_t *nv; 191 nvlist_t *lnv = NULL; 192 193 if (!nvl) { 194 return (EINVAL); 195 } 196 197 *nvl = NULL; 198 199 ret = nvlist_alloc(&nv, NV_UNIQUE_NAME_TYPE, 0); 200 if (ret != 0) { 201 return (ret); 202 } 203 204 /* if there's no config, store an empty list */ 205 if (!cfg) { 206 *nvl = nv; 207 return (0); 208 } 209 210 ret = nvlist_add_uint32(nv, "cfgVersion", cfg->config_version); 211 if (ret == 0) { 212 ret = it_tgtlist_to_nv(cfg->config_tgt_list, &lnv); 213 } 214 215 if ((ret == 0) && (lnv != NULL)) { 216 ret = nvlist_add_nvlist(nv, "targetList", lnv); 217 nvlist_free(lnv); 218 lnv = NULL; 219 } 220 221 if (ret == 0) { 222 ret = it_tpglist_to_nv(cfg->config_tpg_list, &lnv); 223 } 224 225 if ((ret == 0) && (lnv != NULL)) { 226 ret = nvlist_add_nvlist(nv, "tpgList", lnv); 227 nvlist_free(lnv); 228 lnv = NULL; 229 } 230 231 if (ret == 0) { 232 ret = it_inilist_to_nv(cfg->config_ini_list, &lnv); 233 } 234 235 if ((ret == 0) && (lnv != NULL)) { 236 ret = nvlist_add_nvlist(nv, "iniList", lnv); 237 nvlist_free(lnv); 238 lnv = NULL; 239 } 240 241 if (ret == 0) { 242 ret = nvlist_add_nvlist(nv, "globalProperties", 243 cfg->config_global_properties); 244 } 245 246 if (ret == 0) { 247 *nvl = nv; 248 } else { 249 nvlist_free(nv); 250 } 251 252 return (ret); 253 } 254 #endif /* !_KERNEL */ 255 256 /* 257 * nvlist version of config is 3 list-of-list, + 1 proplist. arrays 258 * are interesting, but lists-of-lists are more useful when doing 259 * individual lookups when we later add support for it. Also, no 260 * need to store name in individual struct representation. 261 */ 262 int 263 it_nv_to_config(nvlist_t *nvl, it_config_t **cfg) 264 { 265 int ret; 266 uint32_t intval; 267 nvlist_t *listval; 268 it_config_t *tmpcfg; 269 270 if (!cfg) { 271 return (EINVAL); 272 } 273 274 /* initialize output */ 275 *cfg = NULL; 276 277 tmpcfg = iscsit_zalloc(sizeof (it_config_t)); 278 if (tmpcfg == NULL) { 279 return (ENOMEM); 280 } 281 282 if (!nvl) { 283 /* nothing to decode, but return the empty cfg struct */ 284 ret = nvlist_alloc(&tmpcfg->config_global_properties, 285 NV_UNIQUE_NAME, 0); 286 if (ret != 0) { 287 iscsit_free(tmpcfg, sizeof (it_config_t)); 288 return (ret); 289 } 290 *cfg = tmpcfg; 291 return (0); 292 } 293 294 ret = nvlist_lookup_uint32(nvl, "cfgVersion", &intval); 295 if (ret != 0) { 296 iscsit_free(tmpcfg, sizeof (it_config_t)); 297 return (ret); 298 } 299 300 tmpcfg->config_version = intval; 301 302 ret = nvlist_lookup_nvlist(nvl, "targetList", &listval); 303 if (ret == 0) { 304 /* decode list of it_tgt_t */ 305 ret = it_nv_to_tgtlist(listval, &(tmpcfg->config_tgt_count), 306 &(tmpcfg->config_tgt_list)); 307 } 308 309 ret = nvlist_lookup_nvlist(nvl, "tpgList", &listval); 310 if (ret == 0) { 311 /* decode list of it_tpg_t */ 312 ret = it_nv_to_tpglist(listval, &(tmpcfg->config_tpg_count), 313 &(tmpcfg->config_tpg_list)); 314 } 315 316 ret = nvlist_lookup_nvlist(nvl, "iniList", &listval); 317 if (ret == 0) { 318 /* decode list of initiators */ 319 ret = it_nv_to_inilist(listval, &(tmpcfg->config_ini_count), 320 &(tmpcfg->config_ini_list)); 321 } 322 323 ret = nvlist_lookup_nvlist(nvl, "globalProperties", &listval); 324 if (ret == 0) { 325 /* 326 * don't depend on the original nvlist staying in-scope, 327 * duplicate the nvlist 328 */ 329 ret = nvlist_dup(listval, &(tmpcfg->config_global_properties), 330 0); 331 } else if (ret == ENOENT) { 332 /* 333 * No global properties defined, make an empty list 334 */ 335 ret = nvlist_alloc(&tmpcfg->config_global_properties, 336 NV_UNIQUE_NAME, 0); 337 } 338 339 if (ret == 0) { 340 char **isnsArray = NULL; 341 uint32_t numisns = 0; 342 343 /* 344 * decode the list of iSNS server information to make 345 * references from the kernel simpler. 346 */ 347 if (tmpcfg->config_global_properties) { 348 ret = nvlist_lookup_string_array( 349 tmpcfg->config_global_properties, 350 PROP_ISNS_SERVER, 351 &isnsArray, &numisns); 352 if (ret == 0) { 353 ret = it_array_to_portallist(isnsArray, 354 numisns, ISNS_DEFAULT_SERVER_PORT, 355 &tmpcfg->config_isns_svr_list, 356 &tmpcfg->config_isns_svr_count); 357 } else if (ret == ENOENT) { 358 /* It's OK if we don't have any iSNS servers */ 359 ret = 0; 360 } 361 } 362 } 363 364 if (ret == 0) { 365 *cfg = tmpcfg; 366 } else { 367 it_config_free_cmn(tmpcfg); 368 } 369 370 return (ret); 371 } 372 373 it_tgt_t * 374 it_tgt_lookup(it_config_t *cfg, char *tgt_name) 375 { 376 it_tgt_t *cfg_tgt = NULL; 377 378 for (cfg_tgt = cfg->config_tgt_list; 379 cfg_tgt != NULL; 380 cfg_tgt = cfg_tgt->tgt_next) { 381 if (strncmp(cfg_tgt->tgt_name, tgt_name, 382 MAX_ISCSI_NODENAMELEN) == 0) { 383 return (cfg_tgt); 384 } 385 } 386 387 return (NULL); 388 } 389 390 int 391 it_nv_to_tgtlist(nvlist_t *nvl, uint32_t *count, it_tgt_t **tgtlist) 392 { 393 int ret = 0; 394 it_tgt_t *tgt; 395 it_tgt_t *prev = NULL; 396 nvpair_t *nvp = NULL; 397 nvlist_t *nvt; 398 char *name; 399 400 if (!tgtlist || !count) { 401 return (EINVAL); 402 } 403 404 *tgtlist = NULL; 405 *count = 0; 406 407 if (!nvl) { 408 /* nothing to do */ 409 return (0); 410 } 411 412 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 413 name = nvpair_name(nvp); 414 415 ret = nvpair_value_nvlist(nvp, &nvt); 416 if (ret != 0) { 417 /* invalid entry? */ 418 continue; 419 } 420 421 ret = it_nv_to_tgt(nvt, name, &tgt); 422 if (ret != 0) { 423 break; 424 } 425 426 (*count)++; 427 428 if (*tgtlist == NULL) { 429 *tgtlist = tgt; 430 } else { 431 prev->tgt_next = tgt; 432 } 433 prev = tgt; 434 } 435 436 if (ret != 0) { 437 it_tgt_free_cmn(*tgtlist); 438 *tgtlist = NULL; 439 } 440 441 return (ret); 442 } 443 444 int 445 it_tgtlist_to_nv(it_tgt_t *tgtlist, nvlist_t **nvl) 446 { 447 int ret; 448 it_tgt_t *tgtp = tgtlist; 449 nvlist_t *pnv = NULL; 450 nvlist_t *tnv; 451 452 if (!nvl) { 453 return (EINVAL); 454 } 455 456 if (!tgtlist) { 457 /* nothing to do */ 458 return (0); 459 } 460 461 /* create the target list if required */ 462 if (*nvl == NULL) { 463 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 464 if (ret != 0) { 465 return (ret); 466 } 467 *nvl = pnv; 468 } 469 470 while (tgtp) { 471 ret = it_tgt_to_nv(tgtp, &tnv); 472 473 if (ret != 0) { 474 break; 475 } 476 477 ret = nvlist_add_nvlist(*nvl, tgtp->tgt_name, tnv); 478 479 if (ret != 0) { 480 break; 481 } 482 483 nvlist_free(tnv); 484 485 tgtp = tgtp->tgt_next; 486 } 487 488 if (ret != 0) { 489 if (pnv) { 490 nvlist_free(pnv); 491 *nvl = NULL; 492 } 493 } 494 495 return (ret); 496 } 497 498 int 499 it_tgt_to_nv(it_tgt_t *tgt, nvlist_t **nvl) 500 { 501 int ret; 502 nvlist_t *tnv = NULL; 503 504 if (!nvl) { 505 return (EINVAL); 506 } 507 508 if (!tgt) { 509 /* nothing to do */ 510 return (0); 511 } 512 513 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0); 514 if (ret != 0) { 515 return (ret); 516 } 517 518 if (tgt->tgt_properties) { 519 ret = nvlist_add_nvlist(*nvl, "properties", 520 tgt->tgt_properties); 521 } 522 523 if (ret == 0) { 524 ret = nvlist_add_uint64(*nvl, "generation", 525 tgt->tgt_generation); 526 } 527 528 if (ret == 0) { 529 ret = it_tpgtlist_to_nv(tgt->tgt_tpgt_list, &tnv); 530 } 531 532 if ((ret == 0) && tnv) { 533 ret = nvlist_add_nvlist(*nvl, "tpgtList", tnv); 534 nvlist_free(tnv); 535 } 536 537 if (ret != 0) { 538 nvlist_free(*nvl); 539 *nvl = NULL; 540 } 541 542 return (ret); 543 } 544 545 int 546 it_nv_to_tgt(nvlist_t *nvl, char *name, it_tgt_t **tgt) 547 { 548 int ret; 549 it_tgt_t *ttgt; 550 nvlist_t *listval; 551 uint32_t intval; 552 553 if (!nvl || !tgt || !name) { 554 return (EINVAL); 555 } 556 557 *tgt = NULL; 558 559 ttgt = iscsit_zalloc(sizeof (it_tgt_t)); 560 if (!ttgt) { 561 return (ENOMEM); 562 } 563 564 (void) strlcpy(ttgt->tgt_name, name, sizeof (ttgt->tgt_name)); 565 566 ret = nvlist_lookup_nvlist(nvl, "properties", &listval); 567 if (ret == 0) { 568 /* duplicate list so it does not go out of context */ 569 ret = nvlist_dup(listval, &(ttgt->tgt_properties), 0); 570 } else if (ret == ENOENT) { 571 ret = 0; 572 } 573 574 if (ret == 0) { 575 ret = nvlist_lookup_uint64(nvl, "generation", 576 &(ttgt->tgt_generation)); 577 } else if (ret == ENOENT) { 578 ret = 0; 579 } 580 581 if (ret == 0) { 582 ret = nvlist_lookup_nvlist(nvl, "tpgtList", &listval); 583 } 584 585 if (ret == 0) { 586 ret = it_nv_to_tpgtlist(listval, &intval, 587 &(ttgt->tgt_tpgt_list)); 588 ttgt->tgt_tpgt_count = intval; 589 } else if (ret == ENOENT) { 590 ret = 0; 591 } 592 593 if (ret == 0) { 594 *tgt = ttgt; 595 } else { 596 it_tgt_free_cmn(ttgt); 597 } 598 599 return (ret); 600 } 601 602 int 603 it_tpgt_to_nv(it_tpgt_t *tpgt, nvlist_t **nvl) 604 { 605 int ret; 606 607 if (!nvl) { 608 return (EINVAL); 609 } 610 611 if (!tpgt) { 612 /* nothing to do */ 613 return (0); 614 } 615 616 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0); 617 if (ret != 0) { 618 return (ret); 619 } 620 621 ret = nvlist_add_uint16(*nvl, "tag", tpgt->tpgt_tag); 622 if (ret == 0) { 623 ret = nvlist_add_uint64(*nvl, "generation", 624 tpgt->tpgt_generation); 625 } 626 627 if (ret != 0) { 628 nvlist_free(*nvl); 629 *nvl = NULL; 630 } 631 632 return (ret); 633 } 634 635 int 636 it_nv_to_tpgt(nvlist_t *nvl, char *name, it_tpgt_t **tpgt) 637 { 638 int ret; 639 it_tpgt_t *ptr; 640 641 if (!tpgt || !name) { 642 return (EINVAL); 643 } 644 645 *tpgt = NULL; 646 647 if (!nvl) { 648 return (0); 649 } 650 651 ptr = iscsit_zalloc(sizeof (it_tpgt_t)); 652 if (!ptr) { 653 return (ENOMEM); 654 } 655 656 (void) strlcpy(ptr->tpgt_tpg_name, name, sizeof (ptr->tpgt_tpg_name)); 657 658 ret = nvlist_lookup_uint16(nvl, "tag", &(ptr->tpgt_tag)); 659 if (ret == 0) { 660 ret = nvlist_lookup_uint64(nvl, "generation", 661 &(ptr->tpgt_generation)); 662 } 663 664 if (ret == 0) { 665 *tpgt = ptr; 666 } else { 667 iscsit_free(ptr, sizeof (it_tpgt_t)); 668 } 669 670 return (ret); 671 } 672 673 int 674 it_tpgtlist_to_nv(it_tpgt_t *tpgtlist, nvlist_t **nvl) 675 { 676 int ret; 677 nvlist_t *pnv = NULL; 678 nvlist_t *tnv; 679 it_tpgt_t *ptr = tpgtlist; 680 681 if (!nvl) { 682 return (EINVAL); 683 } 684 685 if (!tpgtlist) { 686 /* nothing to do */ 687 return (0); 688 } 689 690 /* create the target list if required */ 691 if (*nvl == NULL) { 692 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 693 if (ret != 0) { 694 return (ret); 695 } 696 *nvl = pnv; 697 } 698 699 while (ptr) { 700 ret = it_tpgt_to_nv(ptr, &tnv); 701 702 if (ret != 0) { 703 break; 704 } 705 706 ret = nvlist_add_nvlist(*nvl, ptr->tpgt_tpg_name, tnv); 707 708 if (ret != 0) { 709 break; 710 } 711 712 nvlist_free(tnv); 713 714 ptr = ptr->tpgt_next; 715 } 716 717 if (ret != 0) { 718 if (pnv) { 719 nvlist_free(pnv); 720 *nvl = NULL; 721 } 722 } 723 724 return (ret); 725 } 726 727 int 728 it_nv_to_tpgtlist(nvlist_t *nvl, uint32_t *count, it_tpgt_t **tpgtlist) 729 { 730 int ret = 0; 731 it_tpgt_t *tpgt; 732 it_tpgt_t *prev = NULL; 733 nvpair_t *nvp = NULL; 734 nvlist_t *nvt; 735 char *name; 736 737 if (!tpgtlist || !count) { 738 return (EINVAL); 739 } 740 741 *tpgtlist = NULL; 742 *count = 0; 743 744 if (!nvl) { 745 /* nothing to do */ 746 return (0); 747 } 748 749 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 750 name = nvpair_name(nvp); 751 752 ret = nvpair_value_nvlist(nvp, &nvt); 753 if (ret != 0) { 754 /* invalid entry? */ 755 continue; 756 } 757 758 ret = it_nv_to_tpgt(nvt, name, &tpgt); 759 if (ret != 0) { 760 break; 761 } 762 763 (*count)++; 764 765 if (*tpgtlist == NULL) { 766 *tpgtlist = tpgt; 767 } else { 768 prev->tpgt_next = tpgt; 769 } 770 771 prev = tpgt; 772 } 773 774 if (ret != 0) { 775 it_tpgt_free_cmn(*tpgtlist); 776 *tpgtlist = NULL; 777 } 778 779 return (ret); 780 } 781 782 #ifndef _KERNEL 783 int 784 it_tpg_to_nv(it_tpg_t *tpg, nvlist_t **nvl) 785 { 786 int ret; 787 char **portalArray = NULL; 788 int i; 789 it_portal_t *ptr; 790 791 if (!nvl) { 792 return (EINVAL); 793 } 794 795 if (!tpg) { 796 /* nothing to do */ 797 return (0); 798 } 799 800 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0); 801 if (ret != 0) { 802 return (ret); 803 } 804 805 ret = nvlist_add_uint64(*nvl, "generation", tpg->tpg_generation); 806 807 if ((ret == 0) && tpg->tpg_portal_list) { 808 /* add the portals */ 809 portalArray = iscsit_zalloc(tpg->tpg_portal_count * 810 sizeof (it_portal_t)); 811 if (portalArray == NULL) { 812 nvlist_free(*nvl); 813 *nvl = NULL; 814 return (ENOMEM); 815 } 816 817 i = 0; 818 ptr = tpg->tpg_portal_list; 819 820 while (ptr && (i < tpg->tpg_portal_count)) { 821 ret = sockaddr_to_str(&(ptr->portal_addr), 822 &(portalArray[i])); 823 if (ret != 0) { 824 break; 825 } 826 ptr = ptr->portal_next; 827 i++; 828 } 829 } 830 831 if ((ret == 0) && portalArray) { 832 ret = nvlist_add_string_array(*nvl, "portalList", 833 portalArray, i); 834 } 835 836 837 if (portalArray) { 838 while (--i >= 0) { 839 if (portalArray[i]) { 840 iscsit_free(portalArray[i], 841 strlen(portalArray[i] + 1)); 842 } 843 } 844 iscsit_free(portalArray, 845 tpg->tpg_portal_count * sizeof (it_portal_t)); 846 } 847 848 if (ret != 0) { 849 nvlist_free(*nvl); 850 *nvl = NULL; 851 } 852 853 return (ret); 854 } 855 #endif /* !_KERNEL */ 856 857 int 858 it_nv_to_tpg(nvlist_t *nvl, char *name, it_tpg_t **tpg) 859 { 860 int ret; 861 it_tpg_t *ptpg; 862 char **portalArray = NULL; 863 uint32_t count = 0; 864 865 if (!name || !tpg) { 866 return (EINVAL); 867 } 868 869 *tpg = NULL; 870 871 ptpg = iscsit_zalloc(sizeof (it_tpg_t)); 872 if (ptpg == NULL) { 873 return (ENOMEM); 874 } 875 876 (void) strlcpy(ptpg->tpg_name, name, sizeof (ptpg->tpg_name)); 877 878 ret = nvlist_lookup_uint64(nvl, "generation", 879 &(ptpg->tpg_generation)); 880 881 if (ret == 0) { 882 ret = nvlist_lookup_string_array(nvl, "portalList", 883 &portalArray, &count); 884 } 885 886 if (ret == 0) { 887 /* set the portals */ 888 ret = it_array_to_portallist(portalArray, count, 889 ISCSI_LISTEN_PORT, &ptpg->tpg_portal_list, 890 &ptpg->tpg_portal_count); 891 } else if (ret == ENOENT) { 892 ret = 0; 893 } 894 895 if (ret == 0) { 896 *tpg = ptpg; 897 } else { 898 it_tpg_free_cmn(ptpg); 899 } 900 901 return (ret); 902 } 903 904 905 906 907 #ifndef _KERNEL 908 int 909 it_tpglist_to_nv(it_tpg_t *tpglist, nvlist_t **nvl) 910 { 911 int ret; 912 nvlist_t *pnv = NULL; 913 nvlist_t *tnv; 914 it_tpg_t *ptr = tpglist; 915 916 if (!nvl) { 917 return (EINVAL); 918 } 919 920 if (!tpglist) { 921 /* nothing to do */ 922 return (0); 923 } 924 925 /* create the target portal group list if required */ 926 if (*nvl == NULL) { 927 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 928 if (ret != 0) { 929 return (ret); 930 } 931 *nvl = pnv; 932 } 933 934 while (ptr) { 935 ret = it_tpg_to_nv(ptr, &tnv); 936 937 if (ret != 0) { 938 break; 939 } 940 941 ret = nvlist_add_nvlist(*nvl, ptr->tpg_name, tnv); 942 943 if (ret != 0) { 944 break; 945 } 946 947 nvlist_free(tnv); 948 949 ptr = ptr->tpg_next; 950 } 951 952 if (ret != 0) { 953 if (pnv) { 954 nvlist_free(pnv); 955 *nvl = NULL; 956 } 957 } 958 959 return (ret); 960 } 961 #endif /* !_KERNEL */ 962 963 it_tpg_t * 964 it_tpg_lookup(it_config_t *cfg, char *tpg_name) 965 { 966 it_tpg_t *cfg_tpg = NULL; 967 968 for (cfg_tpg = cfg->config_tpg_list; 969 cfg_tpg != NULL; 970 cfg_tpg = cfg_tpg->tpg_next) { 971 if (strncmp(&cfg_tpg->tpg_name[0], tpg_name, 972 MAX_TPG_NAMELEN) == 0) { 973 return (cfg_tpg); 974 } 975 } 976 977 return (NULL); 978 } 979 980 int 981 it_sa_compare(struct sockaddr_storage *sa1, struct sockaddr_storage *sa2) 982 { 983 struct sockaddr_in *sin1, *sin2; 984 struct sockaddr_in6 *sin6_1, *sin6_2; 985 986 /* 987 * XXX - should we check here for IPv4 addrs mapped to v6? 988 * see also iscsit_is_v4_mapped in iscsit_login.c 989 */ 990 991 if (sa1->ss_family != sa2->ss_family) { 992 return (1); 993 } 994 995 /* 996 * sockaddr_in has padding which may not be initialized. 997 * be more specific in the comparison, and don't trust the 998 * caller has fully initialized the structure. 999 */ 1000 if (sa1->ss_family == AF_INET) { 1001 sin1 = (struct sockaddr_in *)sa1; 1002 sin2 = (struct sockaddr_in *)sa2; 1003 if ((bcmp(&sin1->sin_addr, &sin2->sin_addr, 1004 sizeof (struct in_addr)) == 0) && 1005 (sin1->sin_port == sin2->sin_port)) { 1006 return (0); 1007 } 1008 } else if (sa1->ss_family == AF_INET6) { 1009 sin6_1 = (struct sockaddr_in6 *)sa1; 1010 sin6_2 = (struct sockaddr_in6 *)sa2; 1011 if (bcmp(sin6_1, sin6_2, sizeof (struct sockaddr_in6)) == 0) { 1012 return (0); 1013 } 1014 } 1015 1016 return (1); 1017 } 1018 1019 it_portal_t * 1020 it_portal_lookup(it_tpg_t *tpg, struct sockaddr_storage *sa) 1021 { 1022 it_portal_t *cfg_portal; 1023 1024 for (cfg_portal = tpg->tpg_portal_list; 1025 cfg_portal != NULL; 1026 cfg_portal = cfg_portal->portal_next) { 1027 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0) 1028 return (cfg_portal); 1029 } 1030 1031 return (NULL); 1032 } 1033 1034 it_portal_t * 1035 it_sns_svr_lookup(it_config_t *cfg, struct sockaddr_storage *sa) 1036 { 1037 it_portal_t *cfg_portal; 1038 1039 for (cfg_portal = cfg->config_isns_svr_list; 1040 cfg_portal != NULL; 1041 cfg_portal = cfg_portal->portal_next) { 1042 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0) 1043 return (cfg_portal); 1044 } 1045 1046 return (NULL); 1047 } 1048 1049 int 1050 it_nv_to_tpglist(nvlist_t *nvl, uint32_t *count, it_tpg_t **tpglist) 1051 { 1052 int ret = 0; 1053 it_tpg_t *tpg; 1054 it_tpg_t *prev = NULL; 1055 nvpair_t *nvp = NULL; 1056 nvlist_t *nvt; 1057 char *name; 1058 1059 if (!tpglist || !count) { 1060 return (EINVAL); 1061 } 1062 1063 *tpglist = NULL; 1064 *count = 0; 1065 1066 if (!nvl) { 1067 /* nothing to do */ 1068 return (0); 1069 } 1070 1071 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 1072 name = nvpair_name(nvp); 1073 1074 ret = nvpair_value_nvlist(nvp, &nvt); 1075 if (ret != 0) { 1076 /* invalid entry? */ 1077 continue; 1078 } 1079 1080 ret = it_nv_to_tpg(nvt, name, &tpg); 1081 if (ret != 0) { 1082 break; 1083 } 1084 1085 (*count)++; 1086 1087 if (*tpglist == NULL) { 1088 *tpglist = tpg; 1089 } else { 1090 prev->tpg_next = tpg; 1091 } 1092 prev = tpg; 1093 } 1094 1095 if (ret != 0) { 1096 it_tpg_free_cmn(*tpglist); 1097 *tpglist = NULL; 1098 } 1099 1100 return (ret); 1101 } 1102 1103 int 1104 it_ini_to_nv(it_ini_t *ini, nvlist_t **nvl) 1105 { 1106 int ret; 1107 1108 if (!nvl) { 1109 return (EINVAL); 1110 } 1111 1112 if (!ini) { 1113 return (0); 1114 } 1115 1116 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0); 1117 if (ret != 0) { 1118 return (ret); 1119 } 1120 1121 if (ini->ini_properties) { 1122 ret = nvlist_add_nvlist(*nvl, "properties", 1123 ini->ini_properties); 1124 } 1125 1126 if (ret == 0) { 1127 ret = nvlist_add_uint64(*nvl, "generation", 1128 ini->ini_generation); 1129 } else if (ret == ENOENT) { 1130 ret = 0; 1131 } 1132 1133 if (ret != 0) { 1134 nvlist_free(*nvl); 1135 *nvl = NULL; 1136 } 1137 1138 return (ret); 1139 } 1140 1141 int 1142 it_nv_to_ini(nvlist_t *nvl, char *name, it_ini_t **ini) 1143 { 1144 int ret; 1145 it_ini_t *inip; 1146 nvlist_t *listval; 1147 1148 if (!name || !ini) { 1149 return (EINVAL); 1150 } 1151 1152 *ini = NULL; 1153 1154 if (!nvl) { 1155 return (0); 1156 } 1157 1158 inip = iscsit_zalloc(sizeof (it_ini_t)); 1159 if (!inip) { 1160 return (ENOMEM); 1161 } 1162 1163 (void) strlcpy(inip->ini_name, name, sizeof (inip->ini_name)); 1164 1165 ret = nvlist_lookup_nvlist(nvl, "properties", &listval); 1166 if (ret == 0) { 1167 ret = nvlist_dup(listval, &(inip->ini_properties), 0); 1168 } else if (ret == ENOENT) { 1169 ret = 0; 1170 } 1171 1172 if (ret == 0) { 1173 ret = nvlist_lookup_uint64(nvl, "generation", 1174 &(inip->ini_generation)); 1175 } 1176 1177 if (ret == 0) { 1178 *ini = inip; 1179 } else { 1180 it_ini_free_cmn(inip); 1181 } 1182 1183 return (ret); 1184 } 1185 1186 int 1187 it_inilist_to_nv(it_ini_t *inilist, nvlist_t **nvl) 1188 { 1189 int ret; 1190 nvlist_t *pnv = NULL; 1191 nvlist_t *tnv; 1192 it_ini_t *ptr = inilist; 1193 1194 if (!nvl) { 1195 return (EINVAL); 1196 } 1197 1198 if (!inilist) { 1199 return (0); 1200 } 1201 1202 /* create the target list if required */ 1203 if (*nvl == NULL) { 1204 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 1205 if (ret != 0) { 1206 return (ret); 1207 } 1208 *nvl = pnv; 1209 } 1210 1211 while (ptr) { 1212 ret = it_ini_to_nv(ptr, &tnv); 1213 1214 if (ret != 0) { 1215 break; 1216 } 1217 1218 ret = nvlist_add_nvlist(*nvl, ptr->ini_name, tnv); 1219 1220 if (ret != 0) { 1221 break; 1222 } 1223 1224 nvlist_free(tnv); 1225 1226 ptr = ptr->ini_next; 1227 } 1228 1229 if (ret != 0) { 1230 if (pnv) { 1231 nvlist_free(pnv); 1232 *nvl = NULL; 1233 } 1234 } 1235 1236 return (ret); 1237 } 1238 1239 int 1240 it_nv_to_inilist(nvlist_t *nvl, uint32_t *count, it_ini_t **inilist) 1241 { 1242 int ret = 0; 1243 it_ini_t *inip; 1244 it_ini_t *prev = NULL; 1245 nvpair_t *nvp = NULL; 1246 nvlist_t *nvt; 1247 char *name; 1248 1249 if (!inilist || !count) { 1250 return (EINVAL); 1251 } 1252 1253 *inilist = NULL; 1254 *count = 0; 1255 1256 if (!nvl) { 1257 /* nothing to do */ 1258 return (0); 1259 } 1260 1261 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 1262 name = nvpair_name(nvp); 1263 1264 ret = nvpair_value_nvlist(nvp, &nvt); 1265 if (ret != 0) { 1266 /* invalid entry? */ 1267 continue; 1268 } 1269 1270 ret = it_nv_to_ini(nvt, name, &inip); 1271 if (ret != 0) { 1272 break; 1273 } 1274 1275 (*count)++; 1276 1277 if (*inilist == NULL) { 1278 *inilist = inip; 1279 } else { 1280 prev->ini_next = inip; 1281 } 1282 prev = inip; 1283 } 1284 1285 if (ret != 0) { 1286 it_ini_free_cmn(*inilist); 1287 *inilist = NULL; 1288 } 1289 1290 return (ret); 1291 } 1292 1293 /* 1294 * Convert a sockaddr to the string representation, suitable for 1295 * storing in an nvlist or printing out in a list. 1296 */ 1297 #ifndef _KERNEL 1298 int 1299 sockaddr_to_str(struct sockaddr_storage *sa, char **addr) 1300 { 1301 int ret; 1302 char buf[INET6_ADDRSTRLEN + 7]; /* addr : port */ 1303 char pbuf[7]; 1304 const char *bufp; 1305 struct sockaddr_in *sin; 1306 struct sockaddr_in6 *sin6; 1307 uint16_t port; 1308 1309 if (!sa || !addr) { 1310 return (EINVAL); 1311 } 1312 1313 buf[0] = '\0'; 1314 1315 if (sa->ss_family == AF_INET) { 1316 sin = (struct sockaddr_in *)sa; 1317 bufp = inet_ntop(AF_INET, 1318 (const void *)&(sin->sin_addr.s_addr), 1319 buf, sizeof (buf)); 1320 if (bufp == NULL) { 1321 ret = errno; 1322 return (ret); 1323 } 1324 port = ntohs(sin->sin_port); 1325 } else if (sa->ss_family == AF_INET6) { 1326 (void) strlcat(buf, "[", sizeof (buf)); 1327 sin6 = (struct sockaddr_in6 *)sa; 1328 bufp = inet_ntop(AF_INET6, 1329 (const void *)&sin6->sin6_addr.s6_addr, 1330 &buf[1], (sizeof (buf) - 1)); 1331 if (bufp == NULL) { 1332 ret = errno; 1333 return (ret); 1334 } 1335 (void) strlcat(buf, "]", sizeof (buf)); 1336 port = ntohs(sin6->sin6_port); 1337 } else { 1338 return (EINVAL); 1339 } 1340 1341 1342 (void) snprintf(pbuf, sizeof (pbuf), ":%u", port); 1343 (void) strlcat(buf, pbuf, sizeof (buf)); 1344 1345 *addr = strdup(buf); 1346 if (*addr == NULL) { 1347 return (ENOMEM); 1348 } 1349 1350 return (0); 1351 } 1352 #endif /* !_KERNEL */ 1353 1354 int 1355 it_array_to_portallist(char **arr, uint32_t count, uint32_t default_port, 1356 it_portal_t **portallist, uint32_t *list_count) 1357 { 1358 int ret = 0; 1359 int i; 1360 it_portal_t *portal; 1361 it_portal_t *prev = NULL; 1362 it_portal_t *tmp; 1363 1364 if (!arr || !portallist || !list_count) { 1365 return (EINVAL); 1366 } 1367 1368 *list_count = 0; 1369 *portallist = NULL; 1370 1371 for (i = 0; i < count; i++) { 1372 if (!arr[i]) { 1373 /* should never happen */ 1374 continue; 1375 } 1376 portal = iscsit_zalloc(sizeof (it_portal_t)); 1377 if (!portal) { 1378 ret = ENOMEM; 1379 break; 1380 } 1381 if (it_common_convert_sa(arr[i], 1382 &(portal->portal_addr), default_port) == NULL) { 1383 iscsit_free(portal, sizeof (it_portal_t)); 1384 ret = EINVAL; 1385 break; 1386 } 1387 1388 /* make sure no duplicates */ 1389 tmp = *portallist; 1390 while (tmp) { 1391 if (it_sa_compare(&(tmp->portal_addr), 1392 &(portal->portal_addr)) == 0) { 1393 iscsit_free(portal, sizeof (it_portal_t)); 1394 portal = NULL; 1395 break; 1396 } 1397 tmp = tmp->portal_next; 1398 } 1399 1400 if (!portal) { 1401 continue; 1402 } 1403 1404 /* 1405 * The first time through the loop, *portallist == NULL 1406 * because we assigned it to NULL above. Subsequently 1407 * prev will have been set. Therefor it's OK to put 1408 * lint override before prev->portal_next assignment. 1409 */ 1410 if (*portallist == NULL) { 1411 *portallist = portal; 1412 } else { 1413 prev->portal_next = portal; 1414 } 1415 1416 prev = portal; 1417 (*list_count)++; 1418 } 1419 1420 return (ret); 1421 } 1422 1423 /* 1424 * Function: it_config_free_cmn() 1425 * 1426 * Free any resources associated with the it_config_t structure. 1427 * 1428 * Parameters: 1429 * cfg A C representation of the current iSCSI configuration 1430 */ 1431 void 1432 it_config_free_cmn(it_config_t *cfg) 1433 { 1434 if (!cfg) { 1435 return; 1436 } 1437 1438 if (cfg->config_tgt_list) { 1439 it_tgt_free_cmn(cfg->config_tgt_list); 1440 } 1441 1442 if (cfg->config_tpg_list) { 1443 it_tpg_free_cmn(cfg->config_tpg_list); 1444 } 1445 1446 if (cfg->config_ini_list) { 1447 it_ini_free_cmn(cfg->config_ini_list); 1448 } 1449 1450 if (cfg->config_global_properties) { 1451 nvlist_free(cfg->config_global_properties); 1452 } 1453 1454 if (cfg->config_isns_svr_list) { 1455 it_portal_t *pp = cfg->config_isns_svr_list; 1456 it_portal_t *pp_next; 1457 1458 while (pp) { 1459 pp_next = pp->portal_next; 1460 iscsit_free(pp, sizeof (it_portal_t)); 1461 pp = pp_next; 1462 } 1463 } 1464 1465 iscsit_free(cfg, sizeof (it_config_t)); 1466 } 1467 1468 /* 1469 * Function: it_tgt_free_cmn() 1470 * 1471 * Frees an it_tgt_t structure. If tgt_next is not NULL, frees 1472 * all structures in the list. 1473 */ 1474 void 1475 it_tgt_free_cmn(it_tgt_t *tgt) 1476 { 1477 it_tgt_t *tgtp = tgt; 1478 it_tgt_t *next; 1479 1480 if (!tgt) { 1481 return; 1482 } 1483 1484 while (tgtp) { 1485 next = tgtp->tgt_next; 1486 1487 if (tgtp->tgt_tpgt_list) { 1488 it_tpgt_free_cmn(tgtp->tgt_tpgt_list); 1489 } 1490 1491 if (tgtp->tgt_properties) { 1492 nvlist_free(tgtp->tgt_properties); 1493 } 1494 1495 iscsit_free(tgtp, sizeof (it_tgt_t)); 1496 1497 tgtp = next; 1498 } 1499 } 1500 1501 /* 1502 * Function: it_tpgt_free_cmn() 1503 * 1504 * Deallocates resources of an it_tpgt_t structure. If tpgt->next 1505 * is not NULL, frees all members of the list. 1506 */ 1507 void 1508 it_tpgt_free_cmn(it_tpgt_t *tpgt) 1509 { 1510 it_tpgt_t *tpgtp = tpgt; 1511 it_tpgt_t *next; 1512 1513 if (!tpgt) { 1514 return; 1515 } 1516 1517 while (tpgtp) { 1518 next = tpgtp->tpgt_next; 1519 1520 iscsit_free(tpgtp, sizeof (it_tpgt_t)); 1521 1522 tpgtp = next; 1523 } 1524 } 1525 1526 /* 1527 * Function: it_tpg_free_cmn() 1528 * 1529 * Deallocates resources associated with an it_tpg_t structure. 1530 * If tpg->next is not NULL, frees all members of the list. 1531 */ 1532 void 1533 it_tpg_free_cmn(it_tpg_t *tpg) 1534 { 1535 it_tpg_t *tpgp = tpg; 1536 it_tpg_t *next; 1537 it_portal_t *portalp; 1538 it_portal_t *pnext; 1539 1540 while (tpgp) { 1541 next = tpgp->tpg_next; 1542 1543 portalp = tpgp->tpg_portal_list; 1544 1545 while (portalp) { 1546 pnext = portalp->portal_next; 1547 iscsit_free(portalp, sizeof (it_portal_t)); 1548 portalp = pnext; 1549 } 1550 1551 iscsit_free(tpgp, sizeof (it_tpg_t)); 1552 1553 tpgp = next; 1554 } 1555 } 1556 1557 /* 1558 * Function: it_ini_free_cmn() 1559 * 1560 * Deallocates resources of an it_ini_t structure. If ini->next is 1561 * not NULL, frees all members of the list. 1562 */ 1563 void 1564 it_ini_free_cmn(it_ini_t *ini) 1565 { 1566 it_ini_t *inip = ini; 1567 it_ini_t *next; 1568 1569 if (!ini) { 1570 return; 1571 } 1572 1573 while (inip) { 1574 next = inip->ini_next; 1575 1576 if (inip->ini_properties) { 1577 nvlist_free(inip->ini_properties); 1578 } 1579 1580 iscsit_free(inip, sizeof (it_ini_t)); 1581 1582 inip = next; 1583 } 1584 }