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