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