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