dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / common / iscsit / iscsit_common.c
blob69123ebffef026cc45f42a08d3700beda0a2ae36
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++;
829 if (ret == 0) {
830 ret = nvlist_add_string_array(*nvl, "portalList",
831 portalArray, i);
835 while (--i >= 0) {
836 if (portalArray[i]) {
837 iscsit_free(portalArray[i],
838 strlen(portalArray[i] + 1));
841 iscsit_free(portalArray,
842 tpg->tpg_portal_count * sizeof (it_portal_t));
845 if (ret != 0) {
846 nvlist_free(*nvl);
847 *nvl = NULL;
850 return (ret);
852 #endif /* !_KERNEL */
855 it_nv_to_tpg(nvlist_t *nvl, char *name, it_tpg_t **tpg)
857 int ret;
858 it_tpg_t *ptpg;
859 char **portalArray = NULL;
860 uint32_t count = 0;
862 if (!name || !tpg) {
863 return (EINVAL);
866 *tpg = NULL;
868 ptpg = iscsit_zalloc(sizeof (it_tpg_t));
869 if (ptpg == NULL) {
870 return (ENOMEM);
873 (void) strlcpy(ptpg->tpg_name, name, sizeof (ptpg->tpg_name));
875 ret = nvlist_lookup_uint64(nvl, "generation",
876 &(ptpg->tpg_generation));
878 if (ret == 0) {
879 ret = nvlist_lookup_string_array(nvl, "portalList",
880 &portalArray, &count);
883 if (ret == 0) {
884 /* set the portals */
885 ret = it_array_to_portallist(portalArray, count,
886 ISCSI_LISTEN_PORT, &ptpg->tpg_portal_list,
887 &ptpg->tpg_portal_count);
888 } else if (ret == ENOENT) {
889 ret = 0;
892 if (ret == 0) {
893 *tpg = ptpg;
894 } else {
895 it_tpg_free_cmn(ptpg);
898 return (ret);
904 #ifndef _KERNEL
906 it_tpglist_to_nv(it_tpg_t *tpglist, nvlist_t **nvl)
908 int ret;
909 nvlist_t *pnv = NULL;
910 nvlist_t *tnv;
911 it_tpg_t *ptr = tpglist;
913 if (!nvl) {
914 return (EINVAL);
917 if (!tpglist) {
918 /* nothing to do */
919 return (0);
922 /* create the target portal group list if required */
923 if (*nvl == NULL) {
924 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
925 if (ret != 0) {
926 return (ret);
928 *nvl = pnv;
931 while (ptr) {
932 ret = it_tpg_to_nv(ptr, &tnv);
934 if (ret != 0) {
935 break;
938 ret = nvlist_add_nvlist(*nvl, ptr->tpg_name, tnv);
940 if (ret != 0) {
941 break;
944 nvlist_free(tnv);
946 ptr = ptr->tpg_next;
949 if (ret != 0) {
950 if (pnv) {
951 nvlist_free(pnv);
952 *nvl = NULL;
956 return (ret);
958 #endif /* !_KERNEL */
960 it_tpg_t *
961 it_tpg_lookup(it_config_t *cfg, char *tpg_name)
963 it_tpg_t *cfg_tpg = NULL;
965 for (cfg_tpg = cfg->config_tpg_list;
966 cfg_tpg != NULL;
967 cfg_tpg = cfg_tpg->tpg_next) {
968 if (strncmp(&cfg_tpg->tpg_name[0], tpg_name,
969 MAX_TPG_NAMELEN) == 0) {
970 return (cfg_tpg);
974 return (NULL);
978 it_sa_compare(struct sockaddr_storage *sa1, struct sockaddr_storage *sa2)
980 struct sockaddr_in *sin1, *sin2;
981 struct sockaddr_in6 *sin6_1, *sin6_2;
984 * XXX - should we check here for IPv4 addrs mapped to v6?
985 * see also iscsit_is_v4_mapped in iscsit_login.c
988 if (sa1->ss_family != sa2->ss_family) {
989 return (1);
993 * sockaddr_in has padding which may not be initialized.
994 * be more specific in the comparison, and don't trust the
995 * caller has fully initialized the structure.
997 if (sa1->ss_family == AF_INET) {
998 sin1 = (struct sockaddr_in *)sa1;
999 sin2 = (struct sockaddr_in *)sa2;
1000 if ((bcmp(&sin1->sin_addr, &sin2->sin_addr,
1001 sizeof (struct in_addr)) == 0) &&
1002 (sin1->sin_port == sin2->sin_port)) {
1003 return (0);
1005 } else if (sa1->ss_family == AF_INET6) {
1006 sin6_1 = (struct sockaddr_in6 *)sa1;
1007 sin6_2 = (struct sockaddr_in6 *)sa2;
1008 if (bcmp(sin6_1, sin6_2, sizeof (struct sockaddr_in6)) == 0) {
1009 return (0);
1013 return (1);
1016 it_portal_t *
1017 it_portal_lookup(it_tpg_t *tpg, struct sockaddr_storage *sa)
1019 it_portal_t *cfg_portal;
1021 for (cfg_portal = tpg->tpg_portal_list;
1022 cfg_portal != NULL;
1023 cfg_portal = cfg_portal->portal_next) {
1024 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
1025 return (cfg_portal);
1028 return (NULL);
1031 it_portal_t *
1032 it_sns_svr_lookup(it_config_t *cfg, struct sockaddr_storage *sa)
1034 it_portal_t *cfg_portal;
1036 for (cfg_portal = cfg->config_isns_svr_list;
1037 cfg_portal != NULL;
1038 cfg_portal = cfg_portal->portal_next) {
1039 if (it_sa_compare(sa, &cfg_portal->portal_addr) == 0)
1040 return (cfg_portal);
1043 return (NULL);
1047 it_nv_to_tpglist(nvlist_t *nvl, uint32_t *count, it_tpg_t **tpglist)
1049 int ret = 0;
1050 it_tpg_t *tpg;
1051 it_tpg_t *prev = NULL;
1052 nvpair_t *nvp = NULL;
1053 nvlist_t *nvt;
1054 char *name;
1056 if (!tpglist || !count) {
1057 return (EINVAL);
1060 *tpglist = NULL;
1061 *count = 0;
1063 if (!nvl) {
1064 /* nothing to do */
1065 return (0);
1068 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1069 name = nvpair_name(nvp);
1071 ret = nvpair_value_nvlist(nvp, &nvt);
1072 if (ret != 0) {
1073 /* invalid entry? */
1074 continue;
1077 ret = it_nv_to_tpg(nvt, name, &tpg);
1078 if (ret != 0) {
1079 break;
1082 (*count)++;
1084 if (*tpglist == NULL) {
1085 *tpglist = tpg;
1086 } else {
1087 prev->tpg_next = tpg;
1089 prev = tpg;
1092 if (ret != 0) {
1093 it_tpg_free_cmn(*tpglist);
1094 *tpglist = NULL;
1097 return (ret);
1101 it_ini_to_nv(it_ini_t *ini, nvlist_t **nvl)
1103 int ret;
1105 if (!nvl) {
1106 return (EINVAL);
1109 if (!ini) {
1110 return (0);
1113 ret = nvlist_alloc(nvl, NV_UNIQUE_NAME, 0);
1114 if (ret != 0) {
1115 return (ret);
1118 if (ini->ini_properties) {
1119 ret = nvlist_add_nvlist(*nvl, "properties",
1120 ini->ini_properties);
1123 if (ret == 0) {
1124 ret = nvlist_add_uint64(*nvl, "generation",
1125 ini->ini_generation);
1126 } else if (ret == ENOENT) {
1127 ret = 0;
1130 if (ret != 0) {
1131 nvlist_free(*nvl);
1132 *nvl = NULL;
1135 return (ret);
1139 it_nv_to_ini(nvlist_t *nvl, char *name, it_ini_t **ini)
1141 int ret;
1142 it_ini_t *inip;
1143 nvlist_t *listval;
1145 if (!name || !ini) {
1146 return (EINVAL);
1149 *ini = NULL;
1151 if (!nvl) {
1152 return (0);
1155 inip = iscsit_zalloc(sizeof (it_ini_t));
1156 if (!inip) {
1157 return (ENOMEM);
1160 (void) strlcpy(inip->ini_name, name, sizeof (inip->ini_name));
1162 ret = nvlist_lookup_nvlist(nvl, "properties", &listval);
1163 if (ret == 0) {
1164 ret = nvlist_dup(listval, &(inip->ini_properties), 0);
1165 } else if (ret == ENOENT) {
1166 ret = 0;
1169 if (ret == 0) {
1170 ret = nvlist_lookup_uint64(nvl, "generation",
1171 &(inip->ini_generation));
1174 if (ret == 0) {
1175 *ini = inip;
1176 } else {
1177 it_ini_free_cmn(inip);
1180 return (ret);
1184 it_inilist_to_nv(it_ini_t *inilist, nvlist_t **nvl)
1186 int ret;
1187 nvlist_t *pnv = NULL;
1188 nvlist_t *tnv;
1189 it_ini_t *ptr = inilist;
1191 if (!nvl) {
1192 return (EINVAL);
1195 if (!inilist) {
1196 return (0);
1199 /* create the target list if required */
1200 if (*nvl == NULL) {
1201 ret = nvlist_alloc(&pnv, NV_UNIQUE_NAME, 0);
1202 if (ret != 0) {
1203 return (ret);
1205 *nvl = pnv;
1208 while (ptr) {
1209 ret = it_ini_to_nv(ptr, &tnv);
1211 if (ret != 0) {
1212 break;
1215 ret = nvlist_add_nvlist(*nvl, ptr->ini_name, tnv);
1217 if (ret != 0) {
1218 break;
1221 nvlist_free(tnv);
1223 ptr = ptr->ini_next;
1226 if (ret != 0) {
1227 if (pnv) {
1228 nvlist_free(pnv);
1229 *nvl = NULL;
1233 return (ret);
1237 it_nv_to_inilist(nvlist_t *nvl, uint32_t *count, it_ini_t **inilist)
1239 int ret = 0;
1240 it_ini_t *inip;
1241 it_ini_t *prev = NULL;
1242 nvpair_t *nvp = NULL;
1243 nvlist_t *nvt;
1244 char *name;
1246 if (!inilist || !count) {
1247 return (EINVAL);
1250 *inilist = NULL;
1251 *count = 0;
1253 if (!nvl) {
1254 /* nothing to do */
1255 return (0);
1258 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
1259 name = nvpair_name(nvp);
1261 ret = nvpair_value_nvlist(nvp, &nvt);
1262 if (ret != 0) {
1263 /* invalid entry? */
1264 continue;
1267 ret = it_nv_to_ini(nvt, name, &inip);
1268 if (ret != 0) {
1269 break;
1272 (*count)++;
1274 if (*inilist == NULL) {
1275 *inilist = inip;
1276 } else {
1277 prev->ini_next = inip;
1279 prev = inip;
1282 if (ret != 0) {
1283 it_ini_free_cmn(*inilist);
1284 *inilist = NULL;
1287 return (ret);
1291 * Convert a sockaddr to the string representation, suitable for
1292 * storing in an nvlist or printing out in a list.
1294 #ifndef _KERNEL
1296 sockaddr_to_str(struct sockaddr_storage *sa, char **addr)
1298 int ret;
1299 char buf[INET6_ADDRSTRLEN + 7]; /* addr : port */
1300 char pbuf[7];
1301 const char *bufp;
1302 struct sockaddr_in *sin;
1303 struct sockaddr_in6 *sin6;
1304 uint16_t port;
1306 if (!sa || !addr) {
1307 return (EINVAL);
1310 buf[0] = '\0';
1312 if (sa->ss_family == AF_INET) {
1313 sin = (struct sockaddr_in *)sa;
1314 bufp = inet_ntop(AF_INET,
1315 (const void *)&(sin->sin_addr.s_addr),
1316 buf, sizeof (buf));
1317 if (bufp == NULL) {
1318 ret = errno;
1319 return (ret);
1321 port = ntohs(sin->sin_port);
1322 } else if (sa->ss_family == AF_INET6) {
1323 (void) strlcat(buf, "[", sizeof (buf));
1324 sin6 = (struct sockaddr_in6 *)sa;
1325 bufp = inet_ntop(AF_INET6,
1326 (const void *)&sin6->sin6_addr.s6_addr,
1327 &buf[1], (sizeof (buf) - 1));
1328 if (bufp == NULL) {
1329 ret = errno;
1330 return (ret);
1332 (void) strlcat(buf, "]", sizeof (buf));
1333 port = ntohs(sin6->sin6_port);
1334 } else {
1335 return (EINVAL);
1339 (void) snprintf(pbuf, sizeof (pbuf), ":%u", port);
1340 (void) strlcat(buf, pbuf, sizeof (buf));
1342 *addr = strdup(buf);
1343 if (*addr == NULL) {
1344 return (ENOMEM);
1347 return (0);
1349 #endif /* !_KERNEL */
1352 it_array_to_portallist(char **arr, uint32_t count, uint32_t default_port,
1353 it_portal_t **portallist, uint32_t *list_count)
1355 int ret = 0;
1356 int i;
1357 it_portal_t *portal;
1358 it_portal_t *prev = NULL;
1359 it_portal_t *tmp;
1361 if (!arr || !portallist || !list_count) {
1362 return (EINVAL);
1365 *list_count = 0;
1366 *portallist = NULL;
1368 for (i = 0; i < count; i++) {
1369 if (!arr[i]) {
1370 /* should never happen */
1371 continue;
1373 portal = iscsit_zalloc(sizeof (it_portal_t));
1374 if (!portal) {
1375 ret = ENOMEM;
1376 break;
1378 if (it_common_convert_sa(arr[i],
1379 &(portal->portal_addr), default_port) == NULL) {
1380 iscsit_free(portal, sizeof (it_portal_t));
1381 ret = EINVAL;
1382 break;
1385 /* make sure no duplicates */
1386 tmp = *portallist;
1387 while (tmp) {
1388 if (it_sa_compare(&(tmp->portal_addr),
1389 &(portal->portal_addr)) == 0) {
1390 iscsit_free(portal, sizeof (it_portal_t));
1391 portal = NULL;
1392 break;
1394 tmp = tmp->portal_next;
1397 if (!portal) {
1398 continue;
1402 * The first time through the loop, *portallist == NULL
1403 * because we assigned it to NULL above. Subsequently
1404 * prev will have been set. Therefor it's OK to put
1405 * lint override before prev->portal_next assignment.
1407 if (*portallist == NULL) {
1408 *portallist = portal;
1409 } else {
1410 prev->portal_next = portal;
1413 prev = portal;
1414 (*list_count)++;
1417 return (ret);
1421 * Function: it_config_free_cmn()
1423 * Free any resources associated with the it_config_t structure.
1425 * Parameters:
1426 * cfg A C representation of the current iSCSI configuration
1428 void
1429 it_config_free_cmn(it_config_t *cfg)
1431 if (!cfg) {
1432 return;
1435 if (cfg->config_tgt_list) {
1436 it_tgt_free_cmn(cfg->config_tgt_list);
1439 if (cfg->config_tpg_list) {
1440 it_tpg_free_cmn(cfg->config_tpg_list);
1443 if (cfg->config_ini_list) {
1444 it_ini_free_cmn(cfg->config_ini_list);
1447 nvlist_free(cfg->config_global_properties);
1449 if (cfg->config_isns_svr_list) {
1450 it_portal_t *pp = cfg->config_isns_svr_list;
1451 it_portal_t *pp_next;
1453 while (pp) {
1454 pp_next = pp->portal_next;
1455 iscsit_free(pp, sizeof (it_portal_t));
1456 pp = pp_next;
1460 iscsit_free(cfg, sizeof (it_config_t));
1464 * Function: it_tgt_free_cmn()
1466 * Frees an it_tgt_t structure. If tgt_next is not NULL, frees
1467 * all structures in the list.
1469 void
1470 it_tgt_free_cmn(it_tgt_t *tgt)
1472 it_tgt_t *tgtp = tgt;
1473 it_tgt_t *next;
1475 if (!tgt) {
1476 return;
1479 while (tgtp) {
1480 next = tgtp->tgt_next;
1482 if (tgtp->tgt_tpgt_list) {
1483 it_tpgt_free_cmn(tgtp->tgt_tpgt_list);
1486 nvlist_free(tgtp->tgt_properties);
1488 iscsit_free(tgtp, sizeof (it_tgt_t));
1490 tgtp = next;
1495 * Function: it_tpgt_free_cmn()
1497 * Deallocates resources of an it_tpgt_t structure. If tpgt->next
1498 * is not NULL, frees all members of the list.
1500 void
1501 it_tpgt_free_cmn(it_tpgt_t *tpgt)
1503 it_tpgt_t *tpgtp = tpgt;
1504 it_tpgt_t *next;
1506 if (!tpgt) {
1507 return;
1510 while (tpgtp) {
1511 next = tpgtp->tpgt_next;
1513 iscsit_free(tpgtp, sizeof (it_tpgt_t));
1515 tpgtp = next;
1520 * Function: it_tpg_free_cmn()
1522 * Deallocates resources associated with an it_tpg_t structure.
1523 * If tpg->next is not NULL, frees all members of the list.
1525 void
1526 it_tpg_free_cmn(it_tpg_t *tpg)
1528 it_tpg_t *tpgp = tpg;
1529 it_tpg_t *next;
1530 it_portal_t *portalp;
1531 it_portal_t *pnext;
1533 while (tpgp) {
1534 next = tpgp->tpg_next;
1536 portalp = tpgp->tpg_portal_list;
1538 while (portalp) {
1539 pnext = portalp->portal_next;
1540 iscsit_free(portalp, sizeof (it_portal_t));
1541 portalp = pnext;
1544 iscsit_free(tpgp, sizeof (it_tpg_t));
1546 tpgp = next;
1551 * Function: it_ini_free_cmn()
1553 * Deallocates resources of an it_ini_t structure. If ini->next is
1554 * not NULL, frees all members of the list.
1556 void
1557 it_ini_free_cmn(it_ini_t *ini)
1559 it_ini_t *inip = ini;
1560 it_ini_t *next;
1562 if (!ini) {
1563 return;
1566 while (inip) {
1567 next = inip->ini_next;
1569 nvlist_free(inip->ini_properties);
1571 iscsit_free(inip, sizeof (it_ini_t));
1573 inip = next;