8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / common / iscsit / iscsit_common.c
blob35e1d5f9a3ed4ab7e37df903d243aa49601f2dcc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
27 #include <sys/time.h>
29 #if defined(_KERNEL)
30 #include <sys/ddi.h>
31 #include <sys/types.h>
32 #include <sys/sunddi.h>
33 #include <sys/socket.h>
34 #include <inet/ip.h>
35 #include <inet/tcp.h>
36 #else
37 #include <stdio.h>
38 #include <strings.h>
39 #include <stdlib.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #endif
47 #include <sys/iscsit/iscsit_common.h>
48 #include <sys/iscsi_protocol.h>
49 #include <sys/iscsit/isns_protocol.h>
51 void *
52 iscsit_zalloc(size_t size)
54 #if defined(_KERNEL)
55 return (kmem_zalloc(size, KM_SLEEP));
56 #else
57 return (calloc(1, size));
58 #endif
61 void
62 iscsit_free(void *buf, size_t size) /* ARGSUSED */
64 #if defined(_KERNEL)
65 kmem_free(buf, size);
66 #else
67 free(buf);
68 #endif
72 * default_port should be the port to be used, if not specified
73 * as part of the supplied string 'arg'.
76 #define NI_MAXHOST 1025
77 #define NI_MAXSERV 32
80 struct sockaddr_storage *
81 it_common_convert_sa(char *arg, struct sockaddr_storage *buf,
82 uint32_t default_port)
84 /* Why does addrbuf need to be this big!??! XXX */
85 char addrbuf[NI_MAXHOST + NI_MAXSERV + 1];
86 char *addr_str;
87 char *port_str;
88 #ifndef _KERNEL
89 char *errchr;
90 #endif
91 long tmp_port = 0;
92 sa_family_t af;
94 struct sockaddr_in *sin;
95 struct sockaddr_in6 *sin6;
96 struct sockaddr_storage *sa = buf;
98 if (!arg || !buf) {
99 return (NULL);
102 bzero(buf, sizeof (struct sockaddr_storage));
104 /* don't modify the passed-in string */
105 (void) strlcpy(addrbuf, arg, sizeof (addrbuf));
107 addr_str = addrbuf;
109 if (*addr_str == '[') {
111 * An IPv6 address must be inside square brackets
113 port_str = strchr(addr_str, ']');
114 if (!port_str) {
115 /* No closing bracket */
116 return (NULL);
119 /* strip off the square brackets so we can convert */
120 addr_str++;
121 *port_str = '\0';
122 port_str++;
124 if (*port_str == ':') {
125 /* TCP port to follow */
126 port_str++;
127 } else if (*port_str == '\0') {
128 /* No port specified */
129 port_str = NULL;
130 } else {
131 /* malformed */
132 return (NULL);
134 af = AF_INET6;
135 } else {
136 port_str = strchr(addr_str, ':');
137 if (port_str) {
138 *port_str = '\0';
139 port_str++;
141 af = AF_INET;
144 if (port_str) {
145 #if defined(_KERNEL)
146 if (ddi_strtol(port_str, NULL, 10, &tmp_port) != 0) {
147 return (NULL);
149 #else
150 tmp_port = strtol(port_str, &errchr, 10);
151 #endif
152 if (tmp_port < 0 || tmp_port > 65535) {
153 return (NULL);
155 } else {
156 tmp_port = default_port;
159 sa->ss_family = af;
161 sin = (struct sockaddr_in *)sa;
162 if (af == AF_INET) {
163 if (inet_pton(af, addr_str,
164 (void *)&(sin->sin_addr.s_addr)) != 1) {
165 return (NULL);
167 sin->sin_port = htons(tmp_port);
168 } else {
169 sin6 = (struct sockaddr_in6 *)sa;
170 if (inet_pton(af, addr_str,
171 (void *)&(sin6->sin6_addr.s6_addr)) != 1) {
172 return (NULL);
174 sin6->sin6_port = htons(tmp_port);
177 /* successful */
178 return (sa);
182 /* Functions to convert iSCSI target structures to/from nvlists. */
184 #ifndef _KERNEL
186 it_config_to_nv(it_config_t *cfg, nvlist_t **nvl)
188 int ret;
189 nvlist_t *nv;
190 nvlist_t *lnv = NULL;
192 if (!nvl) {
193 return (EINVAL);
196 *nvl = NULL;
198 ret = nvlist_alloc(&nv, NV_UNIQUE_NAME_TYPE, 0);
199 if (ret != 0) {
200 return (ret);
203 /* if there's no config, store an empty list */
204 if (!cfg) {
205 *nvl = nv;
206 return (0);
209 ret = nvlist_add_uint32(nv, "cfgVersion", cfg->config_version);
210 if (ret == 0) {
211 ret = it_tgtlist_to_nv(cfg->config_tgt_list, &lnv);
214 if ((ret == 0) && (lnv != NULL)) {
215 ret = nvlist_add_nvlist(nv, "targetList", lnv);
216 nvlist_free(lnv);
217 lnv = NULL;
220 if (ret == 0) {
221 ret = it_tpglist_to_nv(cfg->config_tpg_list, &lnv);
224 if ((ret == 0) && (lnv != NULL)) {
225 ret = nvlist_add_nvlist(nv, "tpgList", lnv);
226 nvlist_free(lnv);
227 lnv = NULL;
230 if (ret == 0) {
231 ret = it_inilist_to_nv(cfg->config_ini_list, &lnv);
234 if ((ret == 0) && (lnv != NULL)) {
235 ret = nvlist_add_nvlist(nv, "iniList", lnv);
236 nvlist_free(lnv);
237 lnv = NULL;
240 if (ret == 0) {
241 ret = nvlist_add_nvlist(nv, "globalProperties",
242 cfg->config_global_properties);
245 if (ret == 0) {
246 *nvl = nv;
247 } else {
248 nvlist_free(nv);
251 return (ret);
253 #endif /* !_KERNEL */
256 * nvlist version of config is 3 list-of-list, + 1 proplist. arrays
257 * are interesting, but lists-of-lists are more useful when doing
258 * individual lookups when we later add support for it. Also, no
259 * need to store name in individual struct representation.
262 it_nv_to_config(nvlist_t *nvl, it_config_t **cfg)
264 int ret;
265 uint32_t intval;
266 nvlist_t *listval;
267 it_config_t *tmpcfg;
269 if (!cfg) {
270 return (EINVAL);
273 /* initialize output */
274 *cfg = NULL;
276 tmpcfg = iscsit_zalloc(sizeof (it_config_t));
277 if (tmpcfg == NULL) {
278 return (ENOMEM);
281 if (!nvl) {
282 /* nothing to decode, but return the empty cfg struct */
283 ret = nvlist_alloc(&tmpcfg->config_global_properties,
284 NV_UNIQUE_NAME, 0);
285 if (ret != 0) {
286 iscsit_free(tmpcfg, sizeof (it_config_t));
287 return (ret);
289 *cfg = tmpcfg;
290 return (0);
293 ret = nvlist_lookup_uint32(nvl, "cfgVersion", &intval);
294 if (ret != 0) {
295 iscsit_free(tmpcfg, sizeof (it_config_t));
296 return (ret);
299 tmpcfg->config_version = intval;
301 ret = nvlist_lookup_nvlist(nvl, "targetList", &listval);
302 if (ret == 0) {
303 /* decode list of it_tgt_t */
304 ret = it_nv_to_tgtlist(listval, &(tmpcfg->config_tgt_count),
305 &(tmpcfg->config_tgt_list));
308 ret = nvlist_lookup_nvlist(nvl, "tpgList", &listval);
309 if (ret == 0) {
310 /* decode list of it_tpg_t */
311 ret = it_nv_to_tpglist(listval, &(tmpcfg->config_tpg_count),
312 &(tmpcfg->config_tpg_list));
315 ret = nvlist_lookup_nvlist(nvl, "iniList", &listval);
316 if (ret == 0) {
317 /* decode list of initiators */
318 ret = it_nv_to_inilist(listval, &(tmpcfg->config_ini_count),
319 &(tmpcfg->config_ini_list));
322 ret = nvlist_lookup_nvlist(nvl, "globalProperties", &listval);
323 if (ret == 0) {
325 * don't depend on the original nvlist staying in-scope,
326 * duplicate the nvlist
328 ret = nvlist_dup(listval, &(tmpcfg->config_global_properties),
330 } else if (ret == ENOENT) {
332 * No global properties defined, make an empty list
334 ret = nvlist_alloc(&tmpcfg->config_global_properties,
335 NV_UNIQUE_NAME, 0);
338 if (ret == 0) {
339 char **isnsArray = NULL;
340 uint32_t numisns = 0;
343 * decode the list of iSNS server information to make
344 * references from the kernel simpler.
346 if (tmpcfg->config_global_properties) {
347 ret = nvlist_lookup_string_array(
348 tmpcfg->config_global_properties,
349 PROP_ISNS_SERVER,
350 &isnsArray, &numisns);
351 if (ret == 0) {
352 ret = it_array_to_portallist(isnsArray,
353 numisns, ISNS_DEFAULT_SERVER_PORT,
354 &tmpcfg->config_isns_svr_list,
355 &tmpcfg->config_isns_svr_count);
356 } else if (ret == ENOENT) {
357 /* It's OK if we don't have any iSNS servers */
358 ret = 0;
363 if (ret == 0) {
364 *cfg = tmpcfg;
365 } else {
366 it_config_free_cmn(tmpcfg);
369 return (ret);
372 it_tgt_t *
373 it_tgt_lookup(it_config_t *cfg, char *tgt_name)
375 it_tgt_t *cfg_tgt = NULL;
377 for (cfg_tgt = cfg->config_tgt_list;
378 cfg_tgt != NULL;
379 cfg_tgt = cfg_tgt->tgt_next) {
380 if (strncmp(cfg_tgt->tgt_name, tgt_name,
381 MAX_ISCSI_NODENAMELEN) == 0) {
382 return (cfg_tgt);
386 return (NULL);
390 it_nv_to_tgtlist(nvlist_t *nvl, uint32_t *count, it_tgt_t **tgtlist)
392 int ret = 0;
393 it_tgt_t *tgt;
394 it_tgt_t *prev = NULL;
395 nvpair_t *nvp = NULL;
396 nvlist_t *nvt;
397 char *name;
399 if (!tgtlist || !count) {
400 return (EINVAL);
403 *tgtlist = NULL;
404 *count = 0;
406 if (!nvl) {
407 /* nothing to do */
408 return (0);
411 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
412 name = nvpair_name(nvp);
414 ret = nvpair_value_nvlist(nvp, &nvt);
415 if (ret != 0) {
416 /* invalid entry? */
417 continue;
420 ret = it_nv_to_tgt(nvt, name, &tgt);
421 if (ret != 0) {
422 break;
425 (*count)++;
427 if (*tgtlist == NULL) {
428 *tgtlist = tgt;
429 } else {
430 prev->tgt_next = tgt;
432 prev = tgt;
435 if (ret != 0) {
436 it_tgt_free_cmn(*tgtlist);
437 *tgtlist = NULL;
440 return (ret);
444 it_tgtlist_to_nv(it_tgt_t *tgtlist, nvlist_t **nvl)
446 int ret;
447 it_tgt_t *tgtp = tgtlist;
448 nvlist_t *pnv = NULL;
449 nvlist_t *tnv;
451 if (!nvl) {
452 return (EINVAL);
455 if (!tgtlist) {
456 /* nothing to do */
457 return (0);
460 /* create the target list if required */
461 if (*nvl == NULL) {
462 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
463 if (ret != 0) {
464 return (ret);
466 *nvl = pnv;
469 while (tgtp) {
470 ret = it_tgt_to_nv(tgtp, &tnv);
472 if (ret != 0) {
473 break;
476 ret = nvlist_add_nvlist(*nvl, tgtp->tgt_name, tnv);
478 if (ret != 0) {
479 break;
482 nvlist_free(tnv);
484 tgtp = tgtp->tgt_next;
487 if (ret != 0) {
488 if (pnv) {
489 nvlist_free(pnv);
490 *nvl = NULL;
494 return (ret);
498 it_tgt_to_nv(it_tgt_t *tgt, nvlist_t **nvl)
500 int ret;
501 nvlist_t *tnv = NULL;
503 if (!nvl) {
504 return (EINVAL);
507 if (!tgt) {
508 /* nothing to do */
509 return (0);
512 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
513 if (ret != 0) {
514 return (ret);
517 if (tgt->tgt_properties) {
518 ret = nvlist_add_nvlist(*nvl, "properties",
519 tgt->tgt_properties);
522 if (ret == 0) {
523 ret = nvlist_add_uint64(*nvl, "generation",
524 tgt->tgt_generation);
527 if (ret == 0) {
528 ret = it_tpgtlist_to_nv(tgt->tgt_tpgt_list, &tnv);
531 if ((ret == 0) && tnv) {
532 ret = nvlist_add_nvlist(*nvl, "tpgtList", tnv);
533 nvlist_free(tnv);
536 if (ret != 0) {
537 nvlist_free(*nvl);
538 *nvl = NULL;
541 return (ret);
545 it_nv_to_tgt(nvlist_t *nvl, char *name, it_tgt_t **tgt)
547 int ret;
548 it_tgt_t *ttgt;
549 nvlist_t *listval;
550 uint32_t intval;
552 if (!nvl || !tgt || !name) {
553 return (EINVAL);
556 *tgt = NULL;
558 ttgt = iscsit_zalloc(sizeof (it_tgt_t));
559 if (!ttgt) {
560 return (ENOMEM);
563 (void) strlcpy(ttgt->tgt_name, name, sizeof (ttgt->tgt_name));
565 ret = nvlist_lookup_nvlist(nvl, "properties", &listval);
566 if (ret == 0) {
567 /* duplicate list so it does not go out of context */
568 ret = nvlist_dup(listval, &(ttgt->tgt_properties), 0);
569 } else if (ret == ENOENT) {
570 ret = 0;
573 if (ret == 0) {
574 ret = nvlist_lookup_uint64(nvl, "generation",
575 &(ttgt->tgt_generation));
576 } else if (ret == ENOENT) {
577 ret = 0;
580 if (ret == 0) {
581 ret = nvlist_lookup_nvlist(nvl, "tpgtList", &listval);
584 if (ret == 0) {
585 ret = it_nv_to_tpgtlist(listval, &intval,
586 &(ttgt->tgt_tpgt_list));
587 ttgt->tgt_tpgt_count = intval;
588 } else if (ret == ENOENT) {
589 ret = 0;
592 if (ret == 0) {
593 *tgt = ttgt;
594 } else {
595 it_tgt_free_cmn(ttgt);
598 return (ret);
602 it_tpgt_to_nv(it_tpgt_t *tpgt, nvlist_t **nvl)
604 int ret;
606 if (!nvl) {
607 return (EINVAL);
610 if (!tpgt) {
611 /* nothing to do */
612 return (0);
615 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
616 if (ret != 0) {
617 return (ret);
620 ret = nvlist_add_uint16(*nvl, "tag", tpgt->tpgt_tag);
621 if (ret == 0) {
622 ret = nvlist_add_uint64(*nvl, "generation",
623 tpgt->tpgt_generation);
626 if (ret != 0) {
627 nvlist_free(*nvl);
628 *nvl = NULL;
631 return (ret);
635 it_nv_to_tpgt(nvlist_t *nvl, char *name, it_tpgt_t **tpgt)
637 int ret;
638 it_tpgt_t *ptr;
640 if (!tpgt || !name) {
641 return (EINVAL);
644 *tpgt = NULL;
646 if (!nvl) {
647 return (0);
650 ptr = iscsit_zalloc(sizeof (it_tpgt_t));
651 if (!ptr) {
652 return (ENOMEM);
655 (void) strlcpy(ptr->tpgt_tpg_name, name, sizeof (ptr->tpgt_tpg_name));
657 ret = nvlist_lookup_uint16(nvl, "tag", &(ptr->tpgt_tag));
658 if (ret == 0) {
659 ret = nvlist_lookup_uint64(nvl, "generation",
660 &(ptr->tpgt_generation));
663 if (ret == 0) {
664 *tpgt = ptr;
665 } else {
666 iscsit_free(ptr, sizeof (it_tpgt_t));
669 return (ret);
673 it_tpgtlist_to_nv(it_tpgt_t *tpgtlist, nvlist_t **nvl)
675 int ret;
676 nvlist_t *pnv = NULL;
677 nvlist_t *tnv;
678 it_tpgt_t *ptr = tpgtlist;
680 if (!nvl) {
681 return (EINVAL);
684 if (!tpgtlist) {
685 /* nothing to do */
686 return (0);
689 /* create the target list if required */
690 if (*nvl == NULL) {
691 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
692 if (ret != 0) {
693 return (ret);
695 *nvl = pnv;
698 while (ptr) {
699 ret = it_tpgt_to_nv(ptr, &tnv);
701 if (ret != 0) {
702 break;
705 ret = nvlist_add_nvlist(*nvl, ptr->tpgt_tpg_name, tnv);
707 if (ret != 0) {
708 break;
711 nvlist_free(tnv);
713 ptr = ptr->tpgt_next;
716 if (ret != 0) {
717 if (pnv) {
718 nvlist_free(pnv);
719 *nvl = NULL;
723 return (ret);
727 it_nv_to_tpgtlist(nvlist_t *nvl, uint32_t *count, it_tpgt_t **tpgtlist)
729 int ret = 0;
730 it_tpgt_t *tpgt;
731 it_tpgt_t *prev = NULL;
732 nvpair_t *nvp = NULL;
733 nvlist_t *nvt;
734 char *name;
736 if (!tpgtlist || !count) {
737 return (EINVAL);
740 *tpgtlist = NULL;
741 *count = 0;
743 if (!nvl) {
744 /* nothing to do */
745 return (0);
748 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
749 name = nvpair_name(nvp);
751 ret = nvpair_value_nvlist(nvp, &nvt);
752 if (ret != 0) {
753 /* invalid entry? */
754 continue;
757 ret = it_nv_to_tpgt(nvt, name, &tpgt);
758 if (ret != 0) {
759 break;
762 (*count)++;
764 if (*tpgtlist == NULL) {
765 *tpgtlist = tpgt;
766 } else {
767 prev->tpgt_next = tpgt;
770 prev = tpgt;
773 if (ret != 0) {
774 it_tpgt_free_cmn(*tpgtlist);
775 *tpgtlist = NULL;
778 return (ret);
781 #ifndef _KERNEL
783 it_tpg_to_nv(it_tpg_t *tpg, nvlist_t **nvl)
785 int ret;
786 char **portalArray = NULL;
787 int i;
788 it_portal_t *ptr;
790 if (!nvl) {
791 return (EINVAL);
794 if (!tpg) {
795 /* nothing to do */
796 return (0);
799 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
800 if (ret != 0) {
801 return (ret);
804 ret = nvlist_add_uint64(*nvl, "generation", tpg->tpg_generation);
806 if ((ret == 0) && tpg->tpg_portal_list) {
807 /* add the portals */
808 portalArray = iscsit_zalloc(tpg->tpg_portal_count *
809 sizeof (it_portal_t));
810 if (portalArray == NULL) {
811 nvlist_free(*nvl);
812 *nvl = NULL;
813 return (ENOMEM);
816 i = 0;
817 ptr = tpg->tpg_portal_list;
819 while (ptr && (i < tpg->tpg_portal_count)) {
820 ret = sockaddr_to_str(&(ptr->portal_addr),
821 &(portalArray[i]));
822 if (ret != 0) {
823 break;
825 ptr = ptr->portal_next;
826 i++;
830 if ((ret == 0) && portalArray) {
831 ret = nvlist_add_string_array(*nvl, "portalList",
832 portalArray, i);
836 if (portalArray) {
837 while (--i >= 0) {
838 if (portalArray[i]) {
839 iscsit_free(portalArray[i],
840 strlen(portalArray[i] + 1));
843 iscsit_free(portalArray,
844 tpg->tpg_portal_count * sizeof (it_portal_t));
847 if (ret != 0) {
848 nvlist_free(*nvl);
849 *nvl = NULL;
852 return (ret);
854 #endif /* !_KERNEL */
857 it_nv_to_tpg(nvlist_t *nvl, char *name, it_tpg_t **tpg)
859 int ret;
860 it_tpg_t *ptpg;
861 char **portalArray = NULL;
862 uint32_t count = 0;
864 if (!name || !tpg) {
865 return (EINVAL);
868 *tpg = NULL;
870 ptpg = iscsit_zalloc(sizeof (it_tpg_t));
871 if (ptpg == NULL) {
872 return (ENOMEM);
875 (void) strlcpy(ptpg->tpg_name, name, sizeof (ptpg->tpg_name));
877 ret = nvlist_lookup_uint64(nvl, "generation",
878 &(ptpg->tpg_generation));
880 if (ret == 0) {
881 ret = nvlist_lookup_string_array(nvl, "portalList",
882 &portalArray, &count);
885 if (ret == 0) {
886 /* set the portals */
887 ret = it_array_to_portallist(portalArray, count,
888 ISCSI_LISTEN_PORT, &ptpg->tpg_portal_list,
889 &ptpg->tpg_portal_count);
890 } else if (ret == ENOENT) {
891 ret = 0;
894 if (ret == 0) {
895 *tpg = ptpg;
896 } else {
897 it_tpg_free_cmn(ptpg);
900 return (ret);
906 #ifndef _KERNEL
908 it_tpglist_to_nv(it_tpg_t *tpglist, nvlist_t **nvl)
910 int ret;
911 nvlist_t *pnv = NULL;
912 nvlist_t *tnv;
913 it_tpg_t *ptr = tpglist;
915 if (!nvl) {
916 return (EINVAL);
919 if (!tpglist) {
920 /* nothing to do */
921 return (0);
924 /* create the target portal group list if required */
925 if (*nvl == NULL) {
926 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
927 if (ret != 0) {
928 return (ret);
930 *nvl = pnv;
933 while (ptr) {
934 ret = it_tpg_to_nv(ptr, &tnv);
936 if (ret != 0) {
937 break;
940 ret = nvlist_add_nvlist(*nvl, ptr->tpg_name, tnv);
942 if (ret != 0) {
943 break;
946 nvlist_free(tnv);
948 ptr = ptr->tpg_next;
951 if (ret != 0) {
952 if (pnv) {
953 nvlist_free(pnv);
954 *nvl = NULL;
958 return (ret);
960 #endif /* !_KERNEL */
962 it_tpg_t *
963 it_tpg_lookup(it_config_t *cfg, char *tpg_name)
965 it_tpg_t *cfg_tpg = NULL;
967 for (cfg_tpg = cfg->config_tpg_list;
968 cfg_tpg != NULL;
969 cfg_tpg = cfg_tpg->tpg_next) {
970 if (strncmp(&cfg_tpg->tpg_name[0], tpg_name,
971 MAX_TPG_NAMELEN) == 0) {
972 return (cfg_tpg);
976 return (NULL);
980 it_sa_compare(struct sockaddr_storage *sa1, struct sockaddr_storage *sa2)
982 struct sockaddr_in *sin1, *sin2;
983 struct sockaddr_in6 *sin6_1, *sin6_2;
986 * XXX - should we check here for IPv4 addrs mapped to v6?
987 * see also iscsit_is_v4_mapped in iscsit_login.c
990 if (sa1->ss_family != sa2->ss_family) {
991 return (1);
995 * sockaddr_in has padding which may not be initialized.
996 * be more specific in the comparison, and don't trust the
997 * caller has fully initialized the structure.
999 if (sa1->ss_family == AF_INET) {
1000 sin1 = (struct sockaddr_in *)sa1;
1001 sin2 = (struct sockaddr_in *)sa2;
1002 if ((bcmp(&sin1->sin_addr, &sin2->sin_addr,
1003 sizeof (struct in_addr)) == 0) &&
1004 (sin1->sin_port == sin2->sin_port)) {
1005 return (0);
1007 } else if (sa1->ss_family == AF_INET6) {
1008 sin6_1 = (struct sockaddr_in6 *)sa1;
1009 sin6_2 = (struct sockaddr_in6 *)sa2;
1010 if (bcmp(sin6_1, sin6_2, sizeof (struct sockaddr_in6)) == 0) {
1011 return (0);
1015 return (1);
1018 it_portal_t *
1019 it_portal_lookup(it_tpg_t *tpg, struct sockaddr_storage *sa)
1021 it_portal_t *cfg_portal;
1023 for (cfg_portal = tpg->tpg_portal_list;
1024 cfg_portal != NULL;
1025 cfg_portal = cfg_portal->portal_next) {
1026 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
1027 return (cfg_portal);
1030 return (NULL);
1033 it_portal_t *
1034 it_sns_svr_lookup(it_config_t *cfg, struct sockaddr_storage *sa)
1036 it_portal_t *cfg_portal;
1038 for (cfg_portal = cfg->config_isns_svr_list;
1039 cfg_portal != NULL;
1040 cfg_portal = cfg_portal->portal_next) {
1041 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
1042 return (cfg_portal);
1045 return (NULL);
1049 it_nv_to_tpglist(nvlist_t *nvl, uint32_t *count, it_tpg_t **tpglist)
1051 int ret = 0;
1052 it_tpg_t *tpg;
1053 it_tpg_t *prev = NULL;
1054 nvpair_t *nvp = NULL;
1055 nvlist_t *nvt;
1056 char *name;
1058 if (!tpglist || !count) {
1059 return (EINVAL);
1062 *tpglist = NULL;
1063 *count = 0;
1065 if (!nvl) {
1066 /* nothing to do */
1067 return (0);
1070 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1071 name = nvpair_name(nvp);
1073 ret = nvpair_value_nvlist(nvp, &nvt);
1074 if (ret != 0) {
1075 /* invalid entry? */
1076 continue;
1079 ret = it_nv_to_tpg(nvt, name, &tpg);
1080 if (ret != 0) {
1081 break;
1084 (*count)++;
1086 if (*tpglist == NULL) {
1087 *tpglist = tpg;
1088 } else {
1089 prev->tpg_next = tpg;
1091 prev = tpg;
1094 if (ret != 0) {
1095 it_tpg_free_cmn(*tpglist);
1096 *tpglist = NULL;
1099 return (ret);
1103 it_ini_to_nv(it_ini_t *ini, nvlist_t **nvl)
1105 int ret;
1107 if (!nvl) {
1108 return (EINVAL);
1111 if (!ini) {
1112 return (0);
1115 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
1116 if (ret != 0) {
1117 return (ret);
1120 if (ini->ini_properties) {
1121 ret = nvlist_add_nvlist(*nvl, "properties",
1122 ini->ini_properties);
1125 if (ret == 0) {
1126 ret = nvlist_add_uint64(*nvl, "generation",
1127 ini->ini_generation);
1128 } else if (ret == ENOENT) {
1129 ret = 0;
1132 if (ret != 0) {
1133 nvlist_free(*nvl);
1134 *nvl = NULL;
1137 return (ret);
1141 it_nv_to_ini(nvlist_t *nvl, char *name, it_ini_t **ini)
1143 int ret;
1144 it_ini_t *inip;
1145 nvlist_t *listval;
1147 if (!name || !ini) {
1148 return (EINVAL);
1151 *ini = NULL;
1153 if (!nvl) {
1154 return (0);
1157 inip = iscsit_zalloc(sizeof (it_ini_t));
1158 if (!inip) {
1159 return (ENOMEM);
1162 (void) strlcpy(inip->ini_name, name, sizeof (inip->ini_name));
1164 ret = nvlist_lookup_nvlist(nvl, "properties", &listval);
1165 if (ret == 0) {
1166 ret = nvlist_dup(listval, &(inip->ini_properties), 0);
1167 } else if (ret == ENOENT) {
1168 ret = 0;
1171 if (ret == 0) {
1172 ret = nvlist_lookup_uint64(nvl, "generation",
1173 &(inip->ini_generation));
1176 if (ret == 0) {
1177 *ini = inip;
1178 } else {
1179 it_ini_free_cmn(inip);
1182 return (ret);
1186 it_inilist_to_nv(it_ini_t *inilist, nvlist_t **nvl)
1188 int ret;
1189 nvlist_t *pnv = NULL;
1190 nvlist_t *tnv;
1191 it_ini_t *ptr = inilist;
1193 if (!nvl) {
1194 return (EINVAL);
1197 if (!inilist) {
1198 return (0);
1201 /* create the target list if required */
1202 if (*nvl == NULL) {
1203 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
1204 if (ret != 0) {
1205 return (ret);
1207 *nvl = pnv;
1210 while (ptr) {
1211 ret = it_ini_to_nv(ptr, &tnv);
1213 if (ret != 0) {
1214 break;
1217 ret = nvlist_add_nvlist(*nvl, ptr->ini_name, tnv);
1219 if (ret != 0) {
1220 break;
1223 nvlist_free(tnv);
1225 ptr = ptr->ini_next;
1228 if (ret != 0) {
1229 if (pnv) {
1230 nvlist_free(pnv);
1231 *nvl = NULL;
1235 return (ret);
1239 it_nv_to_inilist(nvlist_t *nvl, uint32_t *count, it_ini_t **inilist)
1241 int ret = 0;
1242 it_ini_t *inip;
1243 it_ini_t *prev = NULL;
1244 nvpair_t *nvp = NULL;
1245 nvlist_t *nvt;
1246 char *name;
1248 if (!inilist || !count) {
1249 return (EINVAL);
1252 *inilist = NULL;
1253 *count = 0;
1255 if (!nvl) {
1256 /* nothing to do */
1257 return (0);
1260 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1261 name = nvpair_name(nvp);
1263 ret = nvpair_value_nvlist(nvp, &nvt);
1264 if (ret != 0) {
1265 /* invalid entry? */
1266 continue;
1269 ret = it_nv_to_ini(nvt, name, &inip);
1270 if (ret != 0) {
1271 break;
1274 (*count)++;
1276 if (*inilist == NULL) {
1277 *inilist = inip;
1278 } else {
1279 prev->ini_next = inip;
1281 prev = inip;
1284 if (ret != 0) {
1285 it_ini_free_cmn(*inilist);
1286 *inilist = NULL;
1289 return (ret);
1293 * Convert a sockaddr to the string representation, suitable for
1294 * storing in an nvlist or printing out in a list.
1296 #ifndef _KERNEL
1298 sockaddr_to_str(struct sockaddr_storage *sa, char **addr)
1300 int ret;
1301 char buf[INET6_ADDRSTRLEN + 7]; /* addr : port */
1302 char pbuf[7];
1303 const char *bufp;
1304 struct sockaddr_in *sin;
1305 struct sockaddr_in6 *sin6;
1306 uint16_t port;
1308 if (!sa || !addr) {
1309 return (EINVAL);
1312 buf[0] = '\0';
1314 if (sa->ss_family == AF_INET) {
1315 sin = (struct sockaddr_in *)sa;
1316 bufp = inet_ntop(AF_INET,
1317 (const void *)&(sin->sin_addr.s_addr),
1318 buf, sizeof (buf));
1319 if (bufp == NULL) {
1320 ret = errno;
1321 return (ret);
1323 port = ntohs(sin->sin_port);
1324 } else if (sa->ss_family == AF_INET6) {
1325 (void) strlcat(buf, "[", sizeof (buf));
1326 sin6 = (struct sockaddr_in6 *)sa;
1327 bufp = inet_ntop(AF_INET6,
1328 (const void *)&sin6->sin6_addr.s6_addr,
1329 &buf[1], (sizeof (buf) - 1));
1330 if (bufp == NULL) {
1331 ret = errno;
1332 return (ret);
1334 (void) strlcat(buf, "]", sizeof (buf));
1335 port = ntohs(sin6->sin6_port);
1336 } else {
1337 return (EINVAL);
1341 (void) snprintf(pbuf, sizeof (pbuf), ":%u", port);
1342 (void) strlcat(buf, pbuf, sizeof (buf));
1344 *addr = strdup(buf);
1345 if (*addr == NULL) {
1346 return (ENOMEM);
1349 return (0);
1351 #endif /* !_KERNEL */
1354 it_array_to_portallist(char **arr, uint32_t count, uint32_t default_port,
1355 it_portal_t **portallist, uint32_t *list_count)
1357 int ret = 0;
1358 int i;
1359 it_portal_t *portal;
1360 it_portal_t *prev = NULL;
1361 it_portal_t *tmp;
1363 if (!arr || !portallist || !list_count) {
1364 return (EINVAL);
1367 *list_count = 0;
1368 *portallist = NULL;
1370 for (i = 0; i < count; i++) {
1371 if (!arr[i]) {
1372 /* should never happen */
1373 continue;
1375 portal = iscsit_zalloc(sizeof (it_portal_t));
1376 if (!portal) {
1377 ret = ENOMEM;
1378 break;
1380 if (it_common_convert_sa(arr[i],
1381 &(portal->portal_addr), default_port) == NULL) {
1382 iscsit_free(portal, sizeof (it_portal_t));
1383 ret = EINVAL;
1384 break;
1387 /* make sure no duplicates */
1388 tmp = *portallist;
1389 while (tmp) {
1390 if (it_sa_compare(&(tmp->portal_addr),
1391 &(portal->portal_addr)) == 0) {
1392 iscsit_free(portal, sizeof (it_portal_t));
1393 portal = NULL;
1394 break;
1396 tmp = tmp->portal_next;
1399 if (!portal) {
1400 continue;
1404 * The first time through the loop, *portallist == NULL
1405 * because we assigned it to NULL above. Subsequently
1406 * prev will have been set. Therefor it's OK to put
1407 * lint override before prev->portal_next assignment.
1409 if (*portallist == NULL) {
1410 *portallist = portal;
1411 } else {
1412 prev->portal_next = portal;
1415 prev = portal;
1416 (*list_count)++;
1419 return (ret);
1423 * Function: it_config_free_cmn()
1425 * Free any resources associated with the it_config_t structure.
1427 * Parameters:
1428 * cfg A C representation of the current iSCSI configuration
1430 void
1431 it_config_free_cmn(it_config_t *cfg)
1433 if (!cfg) {
1434 return;
1437 if (cfg->config_tgt_list) {
1438 it_tgt_free_cmn(cfg->config_tgt_list);
1441 if (cfg->config_tpg_list) {
1442 it_tpg_free_cmn(cfg->config_tpg_list);
1445 if (cfg->config_ini_list) {
1446 it_ini_free_cmn(cfg->config_ini_list);
1449 if (cfg->config_global_properties) {
1450 nvlist_free(cfg->config_global_properties);
1453 if (cfg->config_isns_svr_list) {
1454 it_portal_t *pp = cfg->config_isns_svr_list;
1455 it_portal_t *pp_next;
1457 while (pp) {
1458 pp_next = pp->portal_next;
1459 iscsit_free(pp, sizeof (it_portal_t));
1460 pp = pp_next;
1464 iscsit_free(cfg, sizeof (it_config_t));
1468 * Function: it_tgt_free_cmn()
1470 * Frees an it_tgt_t structure. If tgt_next is not NULL, frees
1471 * all structures in the list.
1473 void
1474 it_tgt_free_cmn(it_tgt_t *tgt)
1476 it_tgt_t *tgtp = tgt;
1477 it_tgt_t *next;
1479 if (!tgt) {
1480 return;
1483 while (tgtp) {
1484 next = tgtp->tgt_next;
1486 if (tgtp->tgt_tpgt_list) {
1487 it_tpgt_free_cmn(tgtp->tgt_tpgt_list);
1490 if (tgtp->tgt_properties) {
1491 nvlist_free(tgtp->tgt_properties);
1494 iscsit_free(tgtp, sizeof (it_tgt_t));
1496 tgtp = next;
1501 * Function: it_tpgt_free_cmn()
1503 * Deallocates resources of an it_tpgt_t structure. If tpgt->next
1504 * is not NULL, frees all members of the list.
1506 void
1507 it_tpgt_free_cmn(it_tpgt_t *tpgt)
1509 it_tpgt_t *tpgtp = tpgt;
1510 it_tpgt_t *next;
1512 if (!tpgt) {
1513 return;
1516 while (tpgtp) {
1517 next = tpgtp->tpgt_next;
1519 iscsit_free(tpgtp, sizeof (it_tpgt_t));
1521 tpgtp = next;
1526 * Function: it_tpg_free_cmn()
1528 * Deallocates resources associated with an it_tpg_t structure.
1529 * If tpg->next is not NULL, frees all members of the list.
1531 void
1532 it_tpg_free_cmn(it_tpg_t *tpg)
1534 it_tpg_t *tpgp = tpg;
1535 it_tpg_t *next;
1536 it_portal_t *portalp;
1537 it_portal_t *pnext;
1539 while (tpgp) {
1540 next = tpgp->tpg_next;
1542 portalp = tpgp->tpg_portal_list;
1544 while (portalp) {
1545 pnext = portalp->portal_next;
1546 iscsit_free(portalp, sizeof (it_portal_t));
1547 portalp = pnext;
1550 iscsit_free(tpgp, sizeof (it_tpg_t));
1552 tpgp = next;
1557 * Function: it_ini_free_cmn()
1559 * Deallocates resources of an it_ini_t structure. If ini->next is
1560 * not NULL, frees all members of the list.
1562 void
1563 it_ini_free_cmn(it_ini_t *ini)
1565 it_ini_t *inip = ini;
1566 it_ini_t *next;
1568 if (!ini) {
1569 return;
1572 while (inip) {
1573 next = inip->ini_next;
1575 if (inip->ini_properties) {
1576 nvlist_free(inip->ini_properties);
1579 iscsit_free(inip, sizeof (it_ini_t));
1581 inip = next;