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 if (ret == 0) { 830 ret = nvlist_add_string_array(*nvl, "portalList", 831 portalArray, i); 832 } 833 834 835 while (--i >= 0) { 836 if (portalArray[i]) { 837 iscsit_free(portalArray[i], 838 strlen(portalArray[i] + 1)); 839 } 840 } 841 iscsit_free(portalArray, 842 tpg->tpg_portal_count * sizeof (it_portal_t)); 843 } 844 845 if (ret != 0) { 846 nvlist_free(*nvl); 847 *nvl = NULL; 848 } 849 850 return (ret); 851 } 852 #endif /* !_KERNEL */ 853 854 int 855 it_nv_to_tpg(nvlist_t *nvl, char *name, it_tpg_t **tpg) 856 { 857 int ret; 858 it_tpg_t *ptpg; 859 char **portalArray = NULL; 860 uint32_t count = 0; 861 862 if (!name || !tpg) { 863 return (EINVAL); 864 } 865 866 *tpg = NULL; 867 868 ptpg = iscsit_zalloc(sizeof (it_tpg_t)); 869 if (ptpg == NULL) { 870 return (ENOMEM); 871 } 872 873 (void) strlcpy(ptpg->tpg_name, name, sizeof (ptpg->tpg_name)); 874 875 ret = nvlist_lookup_uint64(nvl, "generation", 876 &(ptpg->tpg_generation)); 877 878 if (ret == 0) { 879 ret = nvlist_lookup_string_array(nvl, "portalList", 880 &portalArray, &count); 881 } 882 883 if (ret == 0) { 884 /* set the portals */ 885 ret = it_array_to_portallist(portalArray, count, 886 ISCSI_LISTEN_PORT, &ptpg->tpg_portal_list, 887 &ptpg->tpg_portal_count); 888 } else if (ret == ENOENT) { 889 ret = 0; 890 } 891 892 if (ret == 0) { 893 *tpg = ptpg; 894 } else { 895 it_tpg_free_cmn(ptpg); 896 } 897 898 return (ret); 899 } 900 901 902 903 904 #ifndef _KERNEL 905 int 906 it_tpglist_to_nv(it_tpg_t *tpglist, nvlist_t **nvl) 907 { 908 int ret; 909 nvlist_t *pnv = NULL; 910 nvlist_t *tnv; 911 it_tpg_t *ptr = tpglist; 912 913 if (!nvl) { 914 return (EINVAL); 915 } 916 917 if (!tpglist) { 918 /* nothing to do */ 919 return (0); 920 } 921 922 /* create the target portal group list if required */ 923 if (*nvl == NULL) { 924 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 925 if (ret != 0) { 926 return (ret); 927 } 928 *nvl = pnv; 929 } 930 931 while (ptr) { 932 ret = it_tpg_to_nv(ptr, &tnv); 933 934 if (ret != 0) { 935 break; 936 } 937 938 ret = nvlist_add_nvlist(*nvl, ptr->tpg_name, tnv); 939 940 if (ret != 0) { 941 break; 942 } 943 944 nvlist_free(tnv); 945 946 ptr = ptr->tpg_next; 947 } 948 949 if (ret != 0) { 950 if (pnv) { 951 nvlist_free(pnv); 952 *nvl = NULL; 953 } 954 } 955 956 return (ret); 957 } 958 #endif /* !_KERNEL */ 959 960 it_tpg_t * 961 it_tpg_lookup(it_config_t *cfg, char *tpg_name) 962 { 963 it_tpg_t *cfg_tpg = NULL; 964 965 for (cfg_tpg = cfg->config_tpg_list; 966 cfg_tpg != NULL; 967 cfg_tpg = cfg_tpg->tpg_next) { 968 if (strncmp(&cfg_tpg->tpg_name[0], tpg_name, 969 MAX_TPG_NAMELEN) == 0) { 970 return (cfg_tpg); 971 } 972 } 973 974 return (NULL); 975 } 976 977 int 978 it_sa_compare(struct sockaddr_storage *sa1, struct sockaddr_storage *sa2) 979 { 980 struct sockaddr_in *sin1, *sin2; 981 struct sockaddr_in6 *sin6_1, *sin6_2; 982 983 /* 984 * XXX - should we check here for IPv4 addrs mapped to v6? 985 * see also iscsit_is_v4_mapped in iscsit_login.c 986 */ 987 988 if (sa1->ss_family != sa2->ss_family) { 989 return (1); 990 } 991 992 /* 993 * sockaddr_in has padding which may not be initialized. 994 * be more specific in the comparison, and don't trust the 995 * caller has fully initialized the structure. 996 */ 997 if (sa1->ss_family == AF_INET) { 998 sin1 = (struct sockaddr_in *)sa1; 999 sin2 = (struct sockaddr_in *)sa2; 1000 if ((bcmp(&sin1->sin_addr, &sin2->sin_addr, 1001 sizeof (struct in_addr)) == 0) && 1002 (sin1->sin_port == sin2->sin_port)) { 1003 return (0); 1004 } 1005 } else if (sa1->ss_family == AF_INET6) { 1006 sin6_1 = (struct sockaddr_in6 *)sa1; 1007 sin6_2 = (struct sockaddr_in6 *)sa2; 1008 if (bcmp(sin6_1, sin6_2, sizeof (struct sockaddr_in6)) == 0) { 1009 return (0); 1010 } 1011 } 1012 1013 return (1); 1014 } 1015 1016 it_portal_t * 1017 it_portal_lookup(it_tpg_t *tpg, struct sockaddr_storage *sa) 1018 { 1019 it_portal_t *cfg_portal; 1020 1021 for (cfg_portal = tpg->tpg_portal_list; 1022 cfg_portal != NULL; 1023 cfg_portal = cfg_portal->portal_next) { 1024 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0) 1025 return (cfg_portal); 1026 } 1027 1028 return (NULL); 1029 } 1030 1031 it_portal_t * 1032 it_sns_svr_lookup(it_config_t *cfg, struct sockaddr_storage *sa) 1033 { 1034 it_portal_t *cfg_portal; 1035 1036 for (cfg_portal = cfg->config_isns_svr_list; 1037 cfg_portal != NULL; 1038 cfg_portal = cfg_portal->portal_next) { 1039 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0) 1040 return (cfg_portal); 1041 } 1042 1043 return (NULL); 1044 } 1045 1046 int 1047 it_nv_to_tpglist(nvlist_t *nvl, uint32_t *count, it_tpg_t **tpglist) 1048 { 1049 int ret = 0; 1050 it_tpg_t *tpg; 1051 it_tpg_t *prev = NULL; 1052 nvpair_t *nvp = NULL; 1053 nvlist_t *nvt; 1054 char *name; 1055 1056 if (!tpglist || !count) { 1057 return (EINVAL); 1058 } 1059 1060 *tpglist = NULL; 1061 *count = 0; 1062 1063 if (!nvl) { 1064 /* nothing to do */ 1065 return (0); 1066 } 1067 1068 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 1069 name = nvpair_name(nvp); 1070 1071 ret = nvpair_value_nvlist(nvp, &nvt); 1072 if (ret != 0) { 1073 /* invalid entry? */ 1074 continue; 1075 } 1076 1077 ret = it_nv_to_tpg(nvt, name, &tpg); 1078 if (ret != 0) { 1079 break; 1080 } 1081 1082 (*count)++; 1083 1084 if (*tpglist == NULL) { 1085 *tpglist = tpg; 1086 } else { 1087 prev->tpg_next = tpg; 1088 } 1089 prev = tpg; 1090 } 1091 1092 if (ret != 0) { 1093 it_tpg_free_cmn(*tpglist); 1094 *tpglist = NULL; 1095 } 1096 1097 return (ret); 1098 } 1099 1100 int 1101 it_ini_to_nv(it_ini_t *ini, nvlist_t **nvl) 1102 { 1103 int ret; 1104 1105 if (!nvl) { 1106 return (EINVAL); 1107 } 1108 1109 if (!ini) { 1110 return (0); 1111 } 1112 1113 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0); 1114 if (ret != 0) { 1115 return (ret); 1116 } 1117 1118 if (ini->ini_properties) { 1119 ret = nvlist_add_nvlist(*nvl, "properties", 1120 ini->ini_properties); 1121 } 1122 1123 if (ret == 0) { 1124 ret = nvlist_add_uint64(*nvl, "generation", 1125 ini->ini_generation); 1126 } else if (ret == ENOENT) { 1127 ret = 0; 1128 } 1129 1130 if (ret != 0) { 1131 nvlist_free(*nvl); 1132 *nvl = NULL; 1133 } 1134 1135 return (ret); 1136 } 1137 1138 int 1139 it_nv_to_ini(nvlist_t *nvl, char *name, it_ini_t **ini) 1140 { 1141 int ret; 1142 it_ini_t *inip; 1143 nvlist_t *listval; 1144 1145 if (!name || !ini) { 1146 return (EINVAL); 1147 } 1148 1149 *ini = NULL; 1150 1151 if (!nvl) { 1152 return (0); 1153 } 1154 1155 inip = iscsit_zalloc(sizeof (it_ini_t)); 1156 if (!inip) { 1157 return (ENOMEM); 1158 } 1159 1160 (void) strlcpy(inip->ini_name, name, sizeof (inip->ini_name)); 1161 1162 ret = nvlist_lookup_nvlist(nvl, "properties", &listval); 1163 if (ret == 0) { 1164 ret = nvlist_dup(listval, &(inip->ini_properties), 0); 1165 } else if (ret == ENOENT) { 1166 ret = 0; 1167 } 1168 1169 if (ret == 0) { 1170 ret = nvlist_lookup_uint64(nvl, "generation", 1171 &(inip->ini_generation)); 1172 } 1173 1174 if (ret == 0) { 1175 *ini = inip; 1176 } else { 1177 it_ini_free_cmn(inip); 1178 } 1179 1180 return (ret); 1181 } 1182 1183 int 1184 it_inilist_to_nv(it_ini_t *inilist, nvlist_t **nvl) 1185 { 1186 int ret; 1187 nvlist_t *pnv = NULL; 1188 nvlist_t *tnv; 1189 it_ini_t *ptr = inilist; 1190 1191 if (!nvl) { 1192 return (EINVAL); 1193 } 1194 1195 if (!inilist) { 1196 return (0); 1197 } 1198 1199 /* create the target list if required */ 1200 if (*nvl == NULL) { 1201 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0); 1202 if (ret != 0) { 1203 return (ret); 1204 } 1205 *nvl = pnv; 1206 } 1207 1208 while (ptr) { 1209 ret = it_ini_to_nv(ptr, &tnv); 1210 1211 if (ret != 0) { 1212 break; 1213 } 1214 1215 ret = nvlist_add_nvlist(*nvl, ptr->ini_name, tnv); 1216 1217 if (ret != 0) { 1218 break; 1219 } 1220 1221 nvlist_free(tnv); 1222 1223 ptr = ptr->ini_next; 1224 } 1225 1226 if (ret != 0) { 1227 if (pnv) { 1228 nvlist_free(pnv); 1229 *nvl = NULL; 1230 } 1231 } 1232 1233 return (ret); 1234 } 1235 1236 int 1237 it_nv_to_inilist(nvlist_t *nvl, uint32_t *count, it_ini_t **inilist) 1238 { 1239 int ret = 0; 1240 it_ini_t *inip; 1241 it_ini_t *prev = NULL; 1242 nvpair_t *nvp = NULL; 1243 nvlist_t *nvt; 1244 char *name; 1245 1246 if (!inilist || !count) { 1247 return (EINVAL); 1248 } 1249 1250 *inilist = NULL; 1251 *count = 0; 1252 1253 if (!nvl) { 1254 /* nothing to do */ 1255 return (0); 1256 } 1257 1258 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) { 1259 name = nvpair_name(nvp); 1260 1261 ret = nvpair_value_nvlist(nvp, &nvt); 1262 if (ret != 0) { 1263 /* invalid entry? */ 1264 continue; 1265 } 1266 1267 ret = it_nv_to_ini(nvt, name, &inip); 1268 if (ret != 0) { 1269 break; 1270 } 1271 1272 (*count)++; 1273 1274 if (*inilist == NULL) { 1275 *inilist = inip; 1276 } else { 1277 prev->ini_next = inip; 1278 } 1279 prev = inip; 1280 } 1281 1282 if (ret != 0) { 1283 it_ini_free_cmn(*inilist); 1284 *inilist = NULL; 1285 } 1286 1287 return (ret); 1288 } 1289 1290 /* 1291 * Convert a sockaddr to the string representation, suitable for 1292 * storing in an nvlist or printing out in a list. 1293 */ 1294 #ifndef _KERNEL 1295 int 1296 sockaddr_to_str(struct sockaddr_storage *sa, char **addr) 1297 { 1298 int ret; 1299 char buf[INET6_ADDRSTRLEN + 7]; /* addr : port */ 1300 char pbuf[7]; 1301 const char *bufp; 1302 struct sockaddr_in *sin; 1303 struct sockaddr_in6 *sin6; 1304 uint16_t port; 1305 1306 if (!sa || !addr) { 1307 return (EINVAL); 1308 } 1309 1310 buf[0] = '\0'; 1311 1312 if (sa->ss_family == AF_INET) { 1313 sin = (struct sockaddr_in *)sa; 1314 bufp = inet_ntop(AF_INET, 1315 (const void *)&(sin->sin_addr.s_addr), 1316 buf, sizeof (buf)); 1317 if (bufp == NULL) { 1318 ret = errno; 1319 return (ret); 1320 } 1321 port = ntohs(sin->sin_port); 1322 } else if (sa->ss_family == AF_INET6) { 1323 (void) strlcat(buf, "[", sizeof (buf)); 1324 sin6 = (struct sockaddr_in6 *)sa; 1325 bufp = inet_ntop(AF_INET6, 1326 (const void *)&sin6->sin6_addr.s6_addr, 1327 &buf[1], (sizeof (buf) - 1)); 1328 if (bufp == NULL) { 1329 ret = errno; 1330 return (ret); 1331 } 1332 (void) strlcat(buf, "]", sizeof (buf)); 1333 port = ntohs(sin6->sin6_port); 1334 } else { 1335 return (EINVAL); 1336 } 1337 1338 1339 (void) snprintf(pbuf, sizeof (pbuf), ":%u", port); 1340 (void) strlcat(buf, pbuf, sizeof (buf)); 1341 1342 *addr = strdup(buf); 1343 if (*addr == NULL) { 1344 return (ENOMEM); 1345 } 1346 1347 return (0); 1348 } 1349 #endif /* !_KERNEL */ 1350 1351 int 1352 it_array_to_portallist(char **arr, uint32_t count, uint32_t default_port, 1353 it_portal_t **portallist, uint32_t *list_count) 1354 { 1355 int ret = 0; 1356 int i; 1357 it_portal_t *portal; 1358 it_portal_t *prev = NULL; 1359 it_portal_t *tmp; 1360 1361 if (!arr || !portallist || !list_count) { 1362 return (EINVAL); 1363 } 1364 1365 *list_count = 0; 1366 *portallist = NULL; 1367 1368 for (i = 0; i < count; i++) { 1369 if (!arr[i]) { 1370 /* should never happen */ 1371 continue; 1372 } 1373 portal = iscsit_zalloc(sizeof (it_portal_t)); 1374 if (!portal) { 1375 ret = ENOMEM; 1376 break; 1377 } 1378 if (it_common_convert_sa(arr[i], 1379 &(portal->portal_addr), default_port) == NULL) { 1380 iscsit_free(portal, sizeof (it_portal_t)); 1381 ret = EINVAL; 1382 break; 1383 } 1384 1385 /* make sure no duplicates */ 1386 tmp = *portallist; 1387 while (tmp) { 1388 if (it_sa_compare(&(tmp->portal_addr), 1389 &(portal->portal_addr)) == 0) { 1390 iscsit_free(portal, sizeof (it_portal_t)); 1391 portal = NULL; 1392 break; 1393 } 1394 tmp = tmp->portal_next; 1395 } 1396 1397 if (!portal) { 1398 continue; 1399 } 1400 1401 /* 1402 * The first time through the loop, *portallist == NULL 1403 * because we assigned it to NULL above. Subsequently 1404 * prev will have been set. Therefor it's OK to put 1405 * lint override before prev->portal_next assignment. 1406 */ 1407 if (*portallist == NULL) { 1408 *portallist = portal; 1409 } else { 1410 prev->portal_next = portal; 1411 } 1412 1413 prev = portal; 1414 (*list_count)++; 1415 } 1416 1417 return (ret); 1418 } 1419 1420 /* 1421 * Function: it_config_free_cmn() 1422 * 1423 * Free any resources associated with the it_config_t structure. 1424 * 1425 * Parameters: 1426 * cfg A C representation of the current iSCSI configuration 1427 */ 1428 void 1429 it_config_free_cmn(it_config_t *cfg) 1430 { 1431 if (!cfg) { 1432 return; 1433 } 1434 1435 if (cfg->config_tgt_list) { 1436 it_tgt_free_cmn(cfg->config_tgt_list); 1437 } 1438 1439 if (cfg->config_tpg_list) { 1440 it_tpg_free_cmn(cfg->config_tpg_list); 1441 } 1442 1443 if (cfg->config_ini_list) { 1444 it_ini_free_cmn(cfg->config_ini_list); 1445 } 1446 1447 if (cfg->config_global_properties) { 1448 nvlist_free(cfg->config_global_properties); 1449 } 1450 1451 if (cfg->config_isns_svr_list) { 1452 it_portal_t *pp = cfg->config_isns_svr_list; 1453 it_portal_t *pp_next; 1454 1455 while (pp) { 1456 pp_next = pp->portal_next; 1457 iscsit_free(pp, sizeof (it_portal_t)); 1458 pp = pp_next; 1459 } 1460 } 1461 1462 iscsit_free(cfg, sizeof (it_config_t)); 1463 } 1464 1465 /* 1466 * Function: it_tgt_free_cmn() 1467 * 1468 * Frees an it_tgt_t structure. If tgt_next is not NULL, frees 1469 * all structures in the list. 1470 */ 1471 void 1472 it_tgt_free_cmn(it_tgt_t *tgt) 1473 { 1474 it_tgt_t *tgtp = tgt; 1475 it_tgt_t *next; 1476 1477 if (!tgt) { 1478 return; 1479 } 1480 1481 while (tgtp) { 1482 next = tgtp->tgt_next; 1483 1484 if (tgtp->tgt_tpgt_list) { 1485 it_tpgt_free_cmn(tgtp->tgt_tpgt_list); 1486 } 1487 1488 if (tgtp->tgt_properties) { 1489 nvlist_free(tgtp->tgt_properties); 1490 } 1491 1492 iscsit_free(tgtp, sizeof (it_tgt_t)); 1493 1494 tgtp = next; 1495 } 1496 } 1497 1498 /* 1499 * Function: it_tpgt_free_cmn() 1500 * 1501 * Deallocates resources of an it_tpgt_t structure. If tpgt->next 1502 * is not NULL, frees all members of the list. 1503 */ 1504 void 1505 it_tpgt_free_cmn(it_tpgt_t *tpgt) 1506 { 1507 it_tpgt_t *tpgtp = tpgt; 1508 it_tpgt_t *next; 1509 1510 if (!tpgt) { 1511 return; 1512 } 1513 1514 while (tpgtp) { 1515 next = tpgtp->tpgt_next; 1516 1517 iscsit_free(tpgtp, sizeof (it_tpgt_t)); 1518 1519 tpgtp = next; 1520 } 1521 } 1522 1523 /* 1524 * Function: it_tpg_free_cmn() 1525 * 1526 * Deallocates resources associated with an it_tpg_t structure. 1527 * If tpg->next is not NULL, frees all members of the list. 1528 */ 1529 void 1530 it_tpg_free_cmn(it_tpg_t *tpg) 1531 { 1532 it_tpg_t *tpgp = tpg; 1533 it_tpg_t *next; 1534 it_portal_t *portalp; 1535 it_portal_t *pnext; 1536 1537 while (tpgp) { 1538 next = tpgp->tpg_next; 1539 1540 portalp = tpgp->tpg_portal_list; 1541 1542 while (portalp) { 1543 pnext = portalp->portal_next; 1544 iscsit_free(portalp, sizeof (it_portal_t)); 1545 portalp = pnext; 1546 } 1547 1548 iscsit_free(tpgp, sizeof (it_tpg_t)); 1549 1550 tpgp = next; 1551 } 1552 } 1553 1554 /* 1555 * Function: it_ini_free_cmn() 1556 * 1557 * Deallocates resources of an it_ini_t structure. If ini->next is 1558 * not NULL, frees all members of the list. 1559 */ 1560 void 1561 it_ini_free_cmn(it_ini_t *ini) 1562 { 1563 it_ini_t *inip = ini; 1564 it_ini_t *next; 1565 1566 if (!ini) { 1567 return; 1568 } 1569 1570 while (inip) { 1571 next = inip->ini_next; 1572 1573 if (inip->ini_properties) { 1574 nvlist_free(inip->ini_properties); 1575 } 1576 1577 iscsit_free(inip, sizeof (it_ini_t)); 1578 1579 inip = next; 1580 } 1581 }