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