xref: /illumos-gate/usr/src/uts/common/io/idm/idm_text.c (revision 2fcabb59)
1a6d42e7dSPeter Dunlap /*
2a6d42e7dSPeter Dunlap  * CDDL HEADER START
3a6d42e7dSPeter Dunlap  *
4a6d42e7dSPeter Dunlap  * The contents of this file are subject to the terms of the
5a6d42e7dSPeter Dunlap  * Common Development and Distribution License (the "License").
6a6d42e7dSPeter Dunlap  * You may not use this file except in compliance with the License.
7a6d42e7dSPeter Dunlap  *
8a6d42e7dSPeter Dunlap  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a6d42e7dSPeter Dunlap  * or http://www.opensolaris.org/os/licensing.
10a6d42e7dSPeter Dunlap  * See the License for the specific language governing permissions
11a6d42e7dSPeter Dunlap  * and limitations under the License.
12a6d42e7dSPeter Dunlap  *
13a6d42e7dSPeter Dunlap  * When distributing Covered Code, include this CDDL HEADER in each
14a6d42e7dSPeter Dunlap  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a6d42e7dSPeter Dunlap  * If applicable, add the following below this CDDL HEADER, with the
16a6d42e7dSPeter Dunlap  * fields enclosed by brackets "[]" replaced with your own identifying
17a6d42e7dSPeter Dunlap  * information: Portions Copyright [yyyy] [name of copyright owner]
18a6d42e7dSPeter Dunlap  *
19a6d42e7dSPeter Dunlap  * CDDL HEADER END
20a6d42e7dSPeter Dunlap  */
21a6d42e7dSPeter Dunlap /*
222ef9abdcSjv  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23a6d42e7dSPeter Dunlap  * Use is subject to license terms.
24a6d42e7dSPeter Dunlap  */
25a6d42e7dSPeter Dunlap 
26a6d42e7dSPeter Dunlap #include <sys/types.h>
27a6d42e7dSPeter Dunlap #include <sys/conf.h>
28a6d42e7dSPeter Dunlap #include <sys/file.h>
29a6d42e7dSPeter Dunlap #include <sys/ddi.h>
30a6d42e7dSPeter Dunlap #include <sys/sunddi.h>
31a6d42e7dSPeter Dunlap #include <sys/sysmacros.h>
32a6d42e7dSPeter Dunlap #include <sys/socket.h>
33a6d42e7dSPeter Dunlap 
34a6d42e7dSPeter Dunlap #include <sys/iscsi_protocol.h>
35a6d42e7dSPeter Dunlap #include <sys/idm/idm.h>
36a6d42e7dSPeter Dunlap #include <sys/idm/idm_text.h>
37a6d42e7dSPeter Dunlap 
38a6d42e7dSPeter Dunlap 
39a6d42e7dSPeter Dunlap extern int
40a6d42e7dSPeter Dunlap iscsi_base64_str_to_binary(char *hstr, int hstr_len,
41a6d42e7dSPeter Dunlap     uint8_t *binary, int binary_buf_len, int *out_len);
42a6d42e7dSPeter Dunlap 
43a6d42e7dSPeter Dunlap 
44a6d42e7dSPeter Dunlap static const char idm_hex_to_ascii[] = "0123456789abcdefABCDEF";
45a6d42e7dSPeter Dunlap 
46a6d42e7dSPeter Dunlap static const idm_kv_xlate_t idm_kvpair_xlate[] = {
47a6d42e7dSPeter Dunlap 	/*
48a6d42e7dSPeter Dunlap 	 * iSCSI Security Text Keys and Authentication Methods
49a6d42e7dSPeter Dunlap 	 */
50a6d42e7dSPeter Dunlap 
51a6d42e7dSPeter Dunlap 	{ KI_AUTH_METHOD, "AuthMethod", KT_LIST_OF_VALUES, B_FALSE },
52a6d42e7dSPeter Dunlap 	/*
53a6d42e7dSPeter Dunlap 	 * For values with RFC comments we need to read the RFC to see
54a6d42e7dSPeter Dunlap 	 * what type is appropriate.  For now just treat the value as
55a6d42e7dSPeter Dunlap 	 * text.
56a6d42e7dSPeter Dunlap 	 */
57a6d42e7dSPeter Dunlap 
58a6d42e7dSPeter Dunlap 	/* Kerberos */
59a6d42e7dSPeter Dunlap 	{ KI_KRB_AP_REQ, "KRB_AP_REQ", KT_TEXT /* RFC1510 */, B_TRUE},
60a6d42e7dSPeter Dunlap 	{ KI_KRB_AP_REP, "KRB_AP_REP", KT_TEXT /* RFC1510 */, B_TRUE},
61a6d42e7dSPeter Dunlap 
62a6d42e7dSPeter Dunlap 	/* SPKM */
63a6d42e7dSPeter Dunlap 	{ KI_SPKM_REQ, "SPKM_REQ", KT_TEXT /* RFC2025 */, B_TRUE},
64a6d42e7dSPeter Dunlap 	{ KI_SPKM_ERROR, "SPKM_ERROR", KT_TEXT /* RFC2025 */, B_TRUE},
65a6d42e7dSPeter Dunlap 	{ KI_SPKM_REP_TI, "SPKM_REP_TI", KT_TEXT /* RFC2025 */, B_TRUE},
66a6d42e7dSPeter Dunlap 	{ KI_SPKM_REP_IT, "SPKM_REP_IT", KT_TEXT /* RFC2025 */, B_TRUE},
67a6d42e7dSPeter Dunlap 
68a6d42e7dSPeter Dunlap 	/*
69a6d42e7dSPeter Dunlap 	 * SRP
70a6d42e7dSPeter Dunlap 	 * U, s, A, B, M, and H(A | M | K) are defined in [RFC2945]
71a6d42e7dSPeter Dunlap 	 */
72a6d42e7dSPeter Dunlap 	{ KI_SRP_U, "SRP_U", KT_TEXT /* <U> */, B_TRUE},
73a6d42e7dSPeter Dunlap 	{ KI_TARGET_AUTH, "TargetAuth", KT_BOOLEAN, B_TRUE},
74a6d42e7dSPeter Dunlap 	{ KI_SRP_GROUP, "SRP_GROUP", KT_LIST_OF_VALUES /* <G1,..> */, B_FALSE},
75a6d42e7dSPeter Dunlap 	{ KI_SRP_A, "SRP_A", KT_TEXT /* <A> */, B_TRUE},
76a6d42e7dSPeter Dunlap 	{ KI_SRP_B, "SRP_B", KT_TEXT /* <B> */, B_TRUE},
77a6d42e7dSPeter Dunlap 	{ KI_SRP_M, "SRP_M", KT_TEXT /* <M> */, B_TRUE},
78a6d42e7dSPeter Dunlap 	{ KI_SRM_HM, "SRP_HM", KT_TEXT /* <H(A | M | K)> */, B_TRUE},
79a6d42e7dSPeter Dunlap 
80a6d42e7dSPeter Dunlap 	/*
81a6d42e7dSPeter Dunlap 	 * CHAP
82a6d42e7dSPeter Dunlap 	 */
83a6d42e7dSPeter Dunlap 	{ KI_CHAP_A, "CHAP_A", KT_LIST_OF_VALUES /* <A1,A2,..> */, B_FALSE },
84a6d42e7dSPeter Dunlap 	{ KI_CHAP_I, "CHAP_I", KT_NUMERICAL /* <I> */, B_TRUE },
85a6d42e7dSPeter Dunlap 	{ KI_CHAP_C, "CHAP_C", KT_BINARY /* <C> */, B_TRUE },
86a6d42e7dSPeter Dunlap 	{ KI_CHAP_N, "CHAP_N", KT_TEXT /* <N> */, B_TRUE },
87a6d42e7dSPeter Dunlap 	{ KI_CHAP_R, "CHAP_R", KT_BINARY /* <N> */, B_TRUE },
88a6d42e7dSPeter Dunlap 
89a6d42e7dSPeter Dunlap 
90a6d42e7dSPeter Dunlap 	/*
91a6d42e7dSPeter Dunlap 	 * ISCSI Operational Parameter Keys
92a6d42e7dSPeter Dunlap 	 */
93a6d42e7dSPeter Dunlap 	{ KI_HEADER_DIGEST, "HeaderDigest", KT_LIST_OF_VALUES, B_FALSE },
94a6d42e7dSPeter Dunlap 	{ KI_DATA_DIGEST, "DataDigest", KT_LIST_OF_VALUES, B_FALSE },
95a6d42e7dSPeter Dunlap 	{ KI_MAX_CONNECTIONS, "MaxConnections", KT_NUMERICAL, B_FALSE },
96a6d42e7dSPeter Dunlap 	{ KI_SEND_TARGETS, "SendTargets", KT_TEXT, B_FALSE },
97a6d42e7dSPeter Dunlap 	{ KI_TARGET_NAME, "TargetName", KT_ISCSI_NAME, B_TRUE},
98a6d42e7dSPeter Dunlap 	{ KI_INITIATOR_NAME, "InitiatorName", KT_ISCSI_NAME, B_TRUE},
99a6d42e7dSPeter Dunlap 	{ KI_TARGET_ALIAS, "TargetAlias", KT_ISCSI_LOCAL_NAME, B_TRUE},
100a6d42e7dSPeter Dunlap 	{ KI_INITIATOR_ALIAS, "InitiatorAlias", KT_ISCSI_LOCAL_NAME, B_TRUE},
101a6d42e7dSPeter Dunlap 	{ KI_TARGET_ADDRESS, "TargetAddress", KT_TEXT, B_TRUE},
102a6d42e7dSPeter Dunlap 	{ KI_TARGET_PORTAL_GROUP_TAG, "TargetPortalGroupTag",
103a6d42e7dSPeter Dunlap 	    KT_NUMERICAL, B_TRUE },
104a6d42e7dSPeter Dunlap 	{ KI_INITIAL_R2T, "InitialR2T", KT_BOOLEAN, B_FALSE },
105a6d42e7dSPeter Dunlap 	{ KI_IMMEDIATE_DATA, "ImmediateData", KT_BOOLEAN, B_FALSE },
106a6d42e7dSPeter Dunlap 	{ KI_MAX_RECV_DATA_SEGMENT_LENGTH, "MaxRecvDataSegmentLength",
107a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 512 to 2^24 - 1 */, B_TRUE },
108a6d42e7dSPeter Dunlap 	{ KI_MAX_BURST_LENGTH, "MaxBurstLength",
109a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE },
110a6d42e7dSPeter Dunlap 	{ KI_FIRST_BURST_LENGTH, "FirstBurstLength",
111a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE },
112a6d42e7dSPeter Dunlap 	{ KI_DEFAULT_TIME_2_WAIT, "DefaultTime2Wait",
113a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 0 to 2600 */, B_FALSE },
114a6d42e7dSPeter Dunlap 	{ KI_DEFAULT_TIME_2_RETAIN, "DefaultTime2Retain",
115a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 0 to 2600 */, B_FALSE },
116a6d42e7dSPeter Dunlap 	{ KI_MAX_OUTSTANDING_R2T, "MaxOutstandingR2T",
117a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 1 to 65535 */, B_FALSE },
118a6d42e7dSPeter Dunlap 	{ KI_DATA_PDU_IN_ORDER, "DataPDUInOrder", KT_BOOLEAN, B_FALSE },
119a6d42e7dSPeter Dunlap 	{ KI_DATA_SEQUENCE_IN_ORDER, "DataSequenceInOrder",
120a6d42e7dSPeter Dunlap 	    KT_BOOLEAN, B_FALSE },
121a6d42e7dSPeter Dunlap 	{ KI_ERROR_RECOVERY_LEVEL, "ErrorRecoveryLevel",
122a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 0 to 2 */, B_FALSE },
123a6d42e7dSPeter Dunlap 	{ KI_SESSION_TYPE, "SessionType", KT_TEXT, B_TRUE },
124a6d42e7dSPeter Dunlap 	{ KI_OFMARKER, "OFMarker", KT_BOOLEAN, B_FALSE },
125a6d42e7dSPeter Dunlap 	{ KI_OFMARKERINT, "OFMarkerInt", KT_NUMERIC_RANGE, B_FALSE },
126a6d42e7dSPeter Dunlap 	{ KI_IFMARKER, "IFMarker", KT_BOOLEAN, B_FALSE },
127a6d42e7dSPeter Dunlap 	{ KI_IFMARKERINT, "IFMarkerInt", KT_NUMERIC_RANGE, B_FALSE },
128a6d42e7dSPeter Dunlap 
129a6d42e7dSPeter Dunlap 	/*
130a6d42e7dSPeter Dunlap 	 * iSER-specific keys
131a6d42e7dSPeter Dunlap 	 */
132a6d42e7dSPeter Dunlap 	{ KI_RDMA_EXTENSIONS, "RDMAExtensions", KT_BOOLEAN, B_FALSE },
133a6d42e7dSPeter Dunlap 	{ KI_TARGET_RECV_DATA_SEGMENT_LENGTH, "TargetRecvDataSegmentLength",
134a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE },
135a6d42e7dSPeter Dunlap 	{ KI_INITIATOR_RECV_DATA_SEGMENT_LENGTH,
136a6d42e7dSPeter Dunlap 	    "InitiatorRecvDataSegmentLength",
137a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE },
138a6d42e7dSPeter Dunlap 	{ KI_MAX_OUTSTANDING_UNEXPECTED_PDUS, "MaxOutstandingUnexpectedPDUs",
139a6d42e7dSPeter Dunlap 	    KT_NUMERICAL /* 2 to 2^32 - 1 | 0 */, B_TRUE },
140a6d42e7dSPeter Dunlap 
141a6d42e7dSPeter Dunlap 	/*
142a6d42e7dSPeter Dunlap 	 * Table terminator. The type KT_TEXT will allow the response
143a6d42e7dSPeter Dunlap 	 * value of "NotUnderstood".
144a6d42e7dSPeter Dunlap 	 */
145a6d42e7dSPeter Dunlap 	{ KI_MAX_KEY, NULL, KT_TEXT, B_TRUE } /* Terminator */
146a6d42e7dSPeter Dunlap };
147a6d42e7dSPeter Dunlap 
148a6d42e7dSPeter Dunlap 
149a6d42e7dSPeter Dunlap #define	TEXTBUF_CHUNKSIZE 8192
150a6d42e7dSPeter Dunlap 
151a6d42e7dSPeter Dunlap typedef struct {
152a6d42e7dSPeter Dunlap 	char	*itb_mem;
153a6d42e7dSPeter Dunlap 	int	itb_offset;
154a6d42e7dSPeter Dunlap 	int	itb_mem_len;
155a6d42e7dSPeter Dunlap } idm_textbuf_t;
156a6d42e7dSPeter Dunlap 
157a6d42e7dSPeter Dunlap /*
158a6d42e7dSPeter Dunlap  * Ignore all but the following keys during security negotiation
159a6d42e7dSPeter Dunlap  *
160a6d42e7dSPeter Dunlap  * SessionType
161a6d42e7dSPeter Dunlap  * InitiatorName
162a6d42e7dSPeter Dunlap  * TargetName
163a6d42e7dSPeter Dunlap  * TargetAddress
164a6d42e7dSPeter Dunlap  * InitiatorAlias
165a6d42e7dSPeter Dunlap  * TargetAlias
166a6d42e7dSPeter Dunlap  * TargetPortalGroupTag
167a6d42e7dSPeter Dunlap  * AuthMethod and associated auth keys
168a6d42e7dSPeter Dunlap  */
169a6d42e7dSPeter Dunlap 
170a6d42e7dSPeter Dunlap static int idm_keyvalue_get_next(char **tb_scan, int *tb_len,
171a6d42e7dSPeter Dunlap     char **key, int *keylen, char **value);
172a6d42e7dSPeter Dunlap 
173a6d42e7dSPeter Dunlap static int idm_nvlist_add_kv(nvlist_t *nvl, const idm_kv_xlate_t *ikvx,
174a6d42e7dSPeter Dunlap     char *value);
175a6d42e7dSPeter Dunlap 
176a6d42e7dSPeter Dunlap static int idm_nvlist_add_string(nvlist_t *nvl,
177a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
178a6d42e7dSPeter Dunlap 
179a6d42e7dSPeter Dunlap static int idm_nvlist_add_boolean(nvlist_t *nvl,
180a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
181a6d42e7dSPeter Dunlap 
182a6d42e7dSPeter Dunlap static int idm_nvlist_add_binary(nvlist_t *nvl,
183a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
184a6d42e7dSPeter Dunlap 
185a6d42e7dSPeter Dunlap static int idm_nvlist_add_large_numerical(nvlist_t *nvl,
186a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
187a6d42e7dSPeter Dunlap 
188a6d42e7dSPeter Dunlap static int idm_nvlist_add_numerical(nvlist_t *nvl,
189a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
190a6d42e7dSPeter Dunlap 
191a6d42e7dSPeter Dunlap static int idm_nvlist_add_numeric_range(nvlist_t *nvl,
192a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
193a6d42e7dSPeter Dunlap 
194a6d42e7dSPeter Dunlap static int idm_nvlist_add_list_of_values(nvlist_t *nvl,
195a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value);
196a6d42e7dSPeter Dunlap 
197a6d42e7dSPeter Dunlap static int idm_itextbuf_add_nvpair(nvpair_t *nvp, idm_textbuf_t *itb);
198a6d42e7dSPeter Dunlap 
199a6d42e7dSPeter Dunlap static int idm_itextbuf_add_string(nvpair_t *nvp,
200a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
201a6d42e7dSPeter Dunlap 
202a6d42e7dSPeter Dunlap static int idm_itextbuf_add_boolean(nvpair_t *nvp,
203a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
204a6d42e7dSPeter Dunlap 
205a6d42e7dSPeter Dunlap static int idm_itextbuf_add_binary(nvpair_t *nvp,
206a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
207a6d42e7dSPeter Dunlap 
208a6d42e7dSPeter Dunlap static int idm_itextbuf_add_large_numerical(nvpair_t *nvp,
209a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
210a6d42e7dSPeter Dunlap 
211a6d42e7dSPeter Dunlap static int idm_itextbuf_add_numerical(nvpair_t *nvp,
212a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
213a6d42e7dSPeter Dunlap 
214a6d42e7dSPeter Dunlap static int idm_itextbuf_add_numeric_range(nvpair_t *nvp,
215a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
216a6d42e7dSPeter Dunlap 
217a6d42e7dSPeter Dunlap static int idm_itextbuf_add_list_of_values(nvpair_t *nvp,
218a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb);
219a6d42e7dSPeter Dunlap 
220a6d42e7dSPeter Dunlap static void textbuf_memcpy(idm_textbuf_t *itb, void *mem, int mem_len);
221a6d42e7dSPeter Dunlap 
222a6d42e7dSPeter Dunlap static void textbuf_strcpy(idm_textbuf_t *itb, char *str);
223a6d42e7dSPeter Dunlap 
224a6d42e7dSPeter Dunlap static void textbuf_append_char(idm_textbuf_t *itb, char c);
225a6d42e7dSPeter Dunlap 
226a6d42e7dSPeter Dunlap static void textbuf_terminate_kvpair(idm_textbuf_t *itb);
227a6d42e7dSPeter Dunlap 
228a6d42e7dSPeter Dunlap static int idm_ascii_to_hex(char *enc_hex_byte, uint8_t *bin_val);
229a6d42e7dSPeter Dunlap 
230a6d42e7dSPeter Dunlap static int idm_base16_str_to_binary(char *hstr, int hstr_len,
231a6d42e7dSPeter Dunlap     uint8_t *binary, int binary_length);
232a6d42e7dSPeter Dunlap 
233a6d42e7dSPeter Dunlap static size_t idm_strcspn(const char *string, const char *charset);
234a6d42e7dSPeter Dunlap 
235a6d42e7dSPeter Dunlap static size_t idm_strnlen(const char *str, size_t maxlen);
236a6d42e7dSPeter Dunlap 
237a6d42e7dSPeter Dunlap /*
238a6d42e7dSPeter Dunlap  * Processes all whole iSCSI name-value pairs in a text buffer and adds
239a6d42e7dSPeter Dunlap  * a corresponding Solaris nvpair_t to the provided nvlist.  If the last
240a6d42e7dSPeter Dunlap  * iSCSI name-value pair in textbuf is truncated (which can occur when
241a6d42e7dSPeter Dunlap  * the request spans multiple PDU's) then upon return textbuf will
242a6d42e7dSPeter Dunlap  * point to the truncated iSCSI name-value pair in the buffer and
243a6d42e7dSPeter Dunlap  * textbuflen will contain the remaining bytes in the buffer.  The
244a6d42e7dSPeter Dunlap  * caller can save off this fragment of the iSCSI name-value pair for
245a6d42e7dSPeter Dunlap  * use when the next PDU in the request arrives.
246a6d42e7dSPeter Dunlap  *
247a6d42e7dSPeter Dunlap  * textbuflen includes the trailing 0x00!
248a6d42e7dSPeter Dunlap  */
249a6d42e7dSPeter Dunlap 
250a6d42e7dSPeter Dunlap int
idm_textbuf_to_nvlist(nvlist_t * nvl,char ** textbuf,int * textbuflen)251a6d42e7dSPeter Dunlap idm_textbuf_to_nvlist(nvlist_t *nvl, char **textbuf, int *textbuflen)
252a6d42e7dSPeter Dunlap {
253a6d42e7dSPeter Dunlap 	int rc = 0;
254a6d42e7dSPeter Dunlap 	char *tbscan, *key, *value;
255a6d42e7dSPeter Dunlap 	int tblen, keylen;
256a6d42e7dSPeter Dunlap 
257a6d42e7dSPeter Dunlap 	tbscan = *textbuf;
258a6d42e7dSPeter Dunlap 	tblen = *textbuflen;
259a6d42e7dSPeter Dunlap 
260a6d42e7dSPeter Dunlap 	for (;;) {
261a6d42e7dSPeter Dunlap 		if ((rc = idm_keyvalue_get_next(&tbscan, &tblen,
262a6d42e7dSPeter Dunlap 		    &key, &keylen, &value)) != 0) {
263a6d42e7dSPeter Dunlap 			/* There was a problem reading the key/value pair */
264a6d42e7dSPeter Dunlap 			break;
265a6d42e7dSPeter Dunlap 		}
266a6d42e7dSPeter Dunlap 
267a6d42e7dSPeter Dunlap 		if ((rc = idm_nvlist_add_keyvalue(nvl,
268a6d42e7dSPeter Dunlap 		    key, keylen, value)) != 0) {
269a6d42e7dSPeter Dunlap 			/* Something was wrong with either the key or value */
270a6d42e7dSPeter Dunlap 			break;
271a6d42e7dSPeter Dunlap 		}
272a6d42e7dSPeter Dunlap 
273a6d42e7dSPeter Dunlap 		if (tblen == 0) {
274a6d42e7dSPeter Dunlap 			/* End of text buffer */
275a6d42e7dSPeter Dunlap 			break;
276a6d42e7dSPeter Dunlap 		}
277a6d42e7dSPeter Dunlap 	}
278a6d42e7dSPeter Dunlap 
279a6d42e7dSPeter Dunlap 	*textbuf = tbscan;
280a6d42e7dSPeter Dunlap 	*textbuflen = tblen;
281a6d42e7dSPeter Dunlap 
282a6d42e7dSPeter Dunlap 	return (rc);
283a6d42e7dSPeter Dunlap }
284a6d42e7dSPeter Dunlap 
285a6d42e7dSPeter Dunlap /*
286a6d42e7dSPeter Dunlap  * If a test buffer starts with an ISCSI name-value pair fragment (a
287a6d42e7dSPeter Dunlap  * continuation from a previous buffer) return the length of the fragment
288a6d42e7dSPeter Dunlap  * contained in this buffer.  We do not handle name-value pairs that span
289a6d42e7dSPeter Dunlap  * more than two buffers so if this buffer does not contain the remainder
290a6d42e7dSPeter Dunlap  * of the name value pair the function will return 0.  If the first
291a6d42e7dSPeter Dunlap  * name-value pair in the buffer is complete the functionw will return 0.
292a6d42e7dSPeter Dunlap  */
293a6d42e7dSPeter Dunlap int
idm_textbuf_to_firstfraglen(void * textbuf,int textbuflen)294a6d42e7dSPeter Dunlap idm_textbuf_to_firstfraglen(void *textbuf, int textbuflen)
295a6d42e7dSPeter Dunlap {
296a6d42e7dSPeter Dunlap 	return (idm_strnlen(textbuf, textbuflen));
297a6d42e7dSPeter Dunlap }
298a6d42e7dSPeter Dunlap 
299a6d42e7dSPeter Dunlap static int
idm_keyvalue_get_next(char ** tb_scan,int * tb_len,char ** key,int * keylen,char ** value)300a6d42e7dSPeter Dunlap idm_keyvalue_get_next(char **tb_scan, int *tb_len,
301a6d42e7dSPeter Dunlap     char **key, int *keylen, char **value)
302a6d42e7dSPeter Dunlap {
303a6d42e7dSPeter Dunlap 	/*
304a6d42e7dSPeter Dunlap 	 * Caller doesn't need "valuelen" returned since "value" will
305a6d42e7dSPeter Dunlap 	 * always be a NULL-terminated string.
306a6d42e7dSPeter Dunlap 	 */
307a6d42e7dSPeter Dunlap 	size_t total_len, valuelen;
308a6d42e7dSPeter Dunlap 
309a6d42e7dSPeter Dunlap 	/*
310a6d42e7dSPeter Dunlap 	 * How many bytes to the first '\0'?  This represents the total
311a6d42e7dSPeter Dunlap 	 * length of our iSCSI key/value pair.
312a6d42e7dSPeter Dunlap 	 */
313a6d42e7dSPeter Dunlap 	total_len = idm_strnlen(*tb_scan, *tb_len);
314a6d42e7dSPeter Dunlap 	if (total_len == *tb_len) {
315a6d42e7dSPeter Dunlap 		/*
316a6d42e7dSPeter Dunlap 		 * No '\0', perhaps this key/value pair is continued in
317a6d42e7dSPeter Dunlap 		 * another buffer
318a6d42e7dSPeter Dunlap 		 */
319a6d42e7dSPeter Dunlap 		return (E2BIG);
320a6d42e7dSPeter Dunlap 	}
321a6d42e7dSPeter Dunlap 
322a6d42e7dSPeter Dunlap 	/*
323a6d42e7dSPeter Dunlap 	 * Found NULL, so this is a possible key-value pair.  At
324a6d42e7dSPeter Dunlap 	 * the same time we've validated that there is actually a
325a6d42e7dSPeter Dunlap 	 * NULL in this string so it's safe to use regular
326a6d42e7dSPeter Dunlap 	 * string functions (i.e. strcpy instead of strncpy)
327a6d42e7dSPeter Dunlap 	 */
328a6d42e7dSPeter Dunlap 	*key = *tb_scan;
329a6d42e7dSPeter Dunlap 	*keylen = idm_strcspn(*tb_scan, "=");
330a6d42e7dSPeter Dunlap 
331a6d42e7dSPeter Dunlap 	if (*keylen == total_len) {
332a6d42e7dSPeter Dunlap 		/* No '=', bad format */
333a6d42e7dSPeter Dunlap 		return (EINVAL);
334a6d42e7dSPeter Dunlap 	}
335a6d42e7dSPeter Dunlap 
336a6d42e7dSPeter Dunlap 	*tb_scan += *keylen + 1; /* Skip the '=' */
337a6d42e7dSPeter Dunlap 	*tb_len -= *keylen + 1;
338a6d42e7dSPeter Dunlap 
339a6d42e7dSPeter Dunlap 	/*
340a6d42e7dSPeter Dunlap 	 * The remaining text after the '=' is the value
341a6d42e7dSPeter Dunlap 	 */
342a6d42e7dSPeter Dunlap 	*value = *tb_scan;
343a6d42e7dSPeter Dunlap 	valuelen = total_len - (*keylen + 1);
344a6d42e7dSPeter Dunlap 
345a6d42e7dSPeter Dunlap 	*tb_scan += valuelen + 1; /* Skip the '\0' */
346a6d42e7dSPeter Dunlap 	*tb_len -= valuelen + 1;
347a6d42e7dSPeter Dunlap 
348a6d42e7dSPeter Dunlap 	return (0);
349a6d42e7dSPeter Dunlap }
350a6d42e7dSPeter Dunlap 
351a6d42e7dSPeter Dunlap const idm_kv_xlate_t *
idm_lookup_kv_xlate(const char * key,int keylen)352a6d42e7dSPeter Dunlap idm_lookup_kv_xlate(const char *key, int keylen)
353a6d42e7dSPeter Dunlap {
354a6d42e7dSPeter Dunlap 	const idm_kv_xlate_t *ikvx = &idm_kvpair_xlate[0];
355a6d42e7dSPeter Dunlap 
356a6d42e7dSPeter Dunlap 	/*
357a6d42e7dSPeter Dunlap 	 * Look for a matching key value in the key/value pair table.
358a6d42e7dSPeter Dunlap 	 * The matching entry in the table will tell us how to encode
359a6d42e7dSPeter Dunlap 	 * the key and value in the nvlist.  If we don't recognize
360a6d42e7dSPeter Dunlap 	 * the key then we will simply encode it in string format.
361a6d42e7dSPeter Dunlap 	 * The login or text request code can generate the appropriate
362a6d42e7dSPeter Dunlap 	 * "not understood" resposne.
363a6d42e7dSPeter Dunlap 	 */
364a6d42e7dSPeter Dunlap 	while (ikvx->ik_key_id != KI_MAX_KEY) {
365a6d42e7dSPeter Dunlap 		/*
366a6d42e7dSPeter Dunlap 		 * Compare strings.  "key" is not NULL-terminated so
367a6d42e7dSPeter Dunlap 		 * use strncmp.  Since we are using strncmp we
368a6d42e7dSPeter Dunlap 		 * need to check that the lengths match, otherwise
369a6d42e7dSPeter Dunlap 		 * we might unintentionally lookup "TargetAddress"
370a6d42e7dSPeter Dunlap 		 * with a key of "Target" (or something similar).
371a6d42e7dSPeter Dunlap 		 *
372a6d42e7dSPeter Dunlap 		 * "value" is NULL-terminated so we can use it as
373a6d42e7dSPeter Dunlap 		 * a regular string.
374a6d42e7dSPeter Dunlap 		 */
375a6d42e7dSPeter Dunlap 		if ((strncmp(ikvx->ik_key_name, key, keylen) == 0) &&
376a6d42e7dSPeter Dunlap 		    (strlen(ikvx->ik_key_name) == keylen)) {
377a6d42e7dSPeter Dunlap 			/* Exit the loop since we found a match */
378a6d42e7dSPeter Dunlap 			break;
379a6d42e7dSPeter Dunlap 		}
380a6d42e7dSPeter Dunlap 
381a6d42e7dSPeter Dunlap 		/* No match, look at the next entry */
382a6d42e7dSPeter Dunlap 		ikvx++;
383a6d42e7dSPeter Dunlap 	}
384a6d42e7dSPeter Dunlap 
385a6d42e7dSPeter Dunlap 	return (ikvx);
386a6d42e7dSPeter Dunlap }
387a6d42e7dSPeter Dunlap 
388a6d42e7dSPeter Dunlap static int
idm_nvlist_add_kv(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)389a6d42e7dSPeter Dunlap idm_nvlist_add_kv(nvlist_t *nvl,  const idm_kv_xlate_t *ikvx, char *value)
390a6d42e7dSPeter Dunlap {
391a6d42e7dSPeter Dunlap 	int rc;
392a6d42e7dSPeter Dunlap 
393a6d42e7dSPeter Dunlap 	switch (ikvx->ik_idm_type) {
394a6d42e7dSPeter Dunlap 	case KT_TEXT:
395a6d42e7dSPeter Dunlap 	case KT_SIMPLE:
396a6d42e7dSPeter Dunlap 	case KT_ISCSI_NAME:
397a6d42e7dSPeter Dunlap 	case KT_ISCSI_LOCAL_NAME:
398a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_string(nvl, ikvx, value);
399a6d42e7dSPeter Dunlap 		break;
400a6d42e7dSPeter Dunlap 	case KT_BOOLEAN:
401a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_boolean(nvl, ikvx, value);
402a6d42e7dSPeter Dunlap 		break;
403a6d42e7dSPeter Dunlap 	case KT_REGULAR_BINARY:
404a6d42e7dSPeter Dunlap 	case KT_LARGE_BINARY:
405a6d42e7dSPeter Dunlap 	case KT_BINARY:
406a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_binary(nvl, ikvx, value);
407a6d42e7dSPeter Dunlap 		break;
408a6d42e7dSPeter Dunlap 	case KT_LARGE_NUMERICAL:
409a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_large_numerical(nvl, ikvx,
410a6d42e7dSPeter Dunlap 		    value);
411a6d42e7dSPeter Dunlap 		break;
412a6d42e7dSPeter Dunlap 	case KT_NUMERICAL:
413a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_numerical(nvl, ikvx,
414a6d42e7dSPeter Dunlap 		    value);
415a6d42e7dSPeter Dunlap 		break;
416a6d42e7dSPeter Dunlap 	case KT_NUMERIC_RANGE:
417a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_numeric_range(nvl, ikvx,
418a6d42e7dSPeter Dunlap 		    value);
419a6d42e7dSPeter Dunlap 		break;
420a6d42e7dSPeter Dunlap 	case KT_LIST_OF_VALUES:
421a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_list_of_values(nvl, ikvx,
422a6d42e7dSPeter Dunlap 		    value);
423a6d42e7dSPeter Dunlap 		break;
424a6d42e7dSPeter Dunlap 	default:
425a6d42e7dSPeter Dunlap 		ASSERT(0); /* This should never happen */
426a6d42e7dSPeter Dunlap 		break;
427a6d42e7dSPeter Dunlap 	}
428a6d42e7dSPeter Dunlap 	if (rc != 0) {
429a6d42e7dSPeter Dunlap 		/* could be one of the text constants */
430a6d42e7dSPeter Dunlap 		rc = idm_nvlist_add_string(nvl, ikvx, value);
431a6d42e7dSPeter Dunlap 	}
432a6d42e7dSPeter Dunlap 
433a6d42e7dSPeter Dunlap 	return (rc);
434a6d42e7dSPeter Dunlap }
435a6d42e7dSPeter Dunlap 
436a6d42e7dSPeter Dunlap static int
idm_nvlist_add_string(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)437a6d42e7dSPeter Dunlap idm_nvlist_add_string(nvlist_t *nvl,
438a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value)
439a6d42e7dSPeter Dunlap {
440a6d42e7dSPeter Dunlap 	return (nvlist_add_string(nvl, ikvx->ik_key_name, value));
441a6d42e7dSPeter Dunlap }
442a6d42e7dSPeter Dunlap 
443a6d42e7dSPeter Dunlap static int
idm_nvlist_add_boolean(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)444a6d42e7dSPeter Dunlap idm_nvlist_add_boolean(nvlist_t *nvl,
445a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value)
446a6d42e7dSPeter Dunlap {
447a6d42e7dSPeter Dunlap 	int rc;
448a6d42e7dSPeter Dunlap 	boolean_t bool_val;
449a6d42e7dSPeter Dunlap 
450a6d42e7dSPeter Dunlap 	if (strcasecmp(value, "Yes") == 0) {
451a6d42e7dSPeter Dunlap 		bool_val = B_TRUE;
452a6d42e7dSPeter Dunlap 	} else if (strcasecmp(value, "No") == 0) {
453a6d42e7dSPeter Dunlap 		bool_val = B_FALSE;
454a6d42e7dSPeter Dunlap 	} else {
455a6d42e7dSPeter Dunlap 		return (EINVAL);
456a6d42e7dSPeter Dunlap 	}
457a6d42e7dSPeter Dunlap 
458a6d42e7dSPeter Dunlap 	rc = nvlist_add_boolean_value(nvl, ikvx->ik_key_name, bool_val);
459a6d42e7dSPeter Dunlap 
460a6d42e7dSPeter Dunlap 	return (rc);
461a6d42e7dSPeter Dunlap }
462a6d42e7dSPeter Dunlap 
463a6d42e7dSPeter Dunlap static boolean_t
kv_is_hex(char * value)464a6d42e7dSPeter Dunlap kv_is_hex(char *value)
465a6d42e7dSPeter Dunlap {
466a6d42e7dSPeter Dunlap 	return ((strncmp(value, "0x", strlen("0x")) == 0) ||
467a6d42e7dSPeter Dunlap 	    (strncmp(value, "0X", strlen("0X")) == 0));
468a6d42e7dSPeter Dunlap }
469a6d42e7dSPeter Dunlap 
470a6d42e7dSPeter Dunlap static boolean_t
kv_is_base64(char * value)471a6d42e7dSPeter Dunlap kv_is_base64(char *value)
472a6d42e7dSPeter Dunlap {
473a6d42e7dSPeter Dunlap 	return ((strncmp(value, "0b", strlen("0b")) == 0) ||
474a6d42e7dSPeter Dunlap 	    (strncmp(value, "0B", strlen("0B")) == 0));
475a6d42e7dSPeter Dunlap }
476a6d42e7dSPeter Dunlap 
477a6d42e7dSPeter Dunlap 
478a6d42e7dSPeter Dunlap static int
idm_nvlist_add_binary(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)479a6d42e7dSPeter Dunlap idm_nvlist_add_binary(nvlist_t *nvl,
480a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value)
481a6d42e7dSPeter Dunlap {
482a6d42e7dSPeter Dunlap 	int		rc;
483a6d42e7dSPeter Dunlap 	int		value_length;
484a6d42e7dSPeter Dunlap 	uint64_t	uint64_value;
485a6d42e7dSPeter Dunlap 	int		binary_length;
486a6d42e7dSPeter Dunlap 	uchar_t		*binary_array;
487a6d42e7dSPeter Dunlap 
488a6d42e7dSPeter Dunlap 	/*
489a6d42e7dSPeter Dunlap 	 * A binary value can be either decimal, hex or base64.  If it's
490a6d42e7dSPeter Dunlap 	 * decimal then the encoded string must be less than 64 bits in
491a6d42e7dSPeter Dunlap 	 * length (8 characters).  In all cases we will convert the
492a6d42e7dSPeter Dunlap 	 * included value to a byte array starting with the MSB.  The
493a6d42e7dSPeter Dunlap 	 * assumption is that values meant to be treated as integers will
494a6d42e7dSPeter Dunlap 	 * use the "numerical" and "large numerical" types.
495a6d42e7dSPeter Dunlap 	 */
496a6d42e7dSPeter Dunlap 	if (kv_is_hex(value)) {
497a6d42e7dSPeter Dunlap 		value += strlen("0x");
498a6d42e7dSPeter Dunlap 		value_length = strlen(value);
499a6d42e7dSPeter Dunlap 		binary_length = (value_length + 1) / 2;
500a6d42e7dSPeter Dunlap 		binary_array = kmem_alloc(binary_length, KM_SLEEP);
501a6d42e7dSPeter Dunlap 
502a6d42e7dSPeter Dunlap 		if (idm_base16_str_to_binary(value, value_length,
503a6d42e7dSPeter Dunlap 		    binary_array, binary_length) != 0) {
504a6d42e7dSPeter Dunlap 			kmem_free(binary_array, binary_length);
505a6d42e7dSPeter Dunlap 			return (EINVAL);
506a6d42e7dSPeter Dunlap 		}
507a6d42e7dSPeter Dunlap 
508a6d42e7dSPeter Dunlap 		rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name,
509a6d42e7dSPeter Dunlap 		    binary_array, binary_length);
510a6d42e7dSPeter Dunlap 
511a6d42e7dSPeter Dunlap 		kmem_free(binary_array, binary_length);
512a6d42e7dSPeter Dunlap 
513a6d42e7dSPeter Dunlap 		return (rc);
514a6d42e7dSPeter Dunlap 
515a6d42e7dSPeter Dunlap 	} else if (kv_is_base64(value)) {
516a6d42e7dSPeter Dunlap 		value += strlen("0b");
517a6d42e7dSPeter Dunlap 		value_length = strlen(value);
518a6d42e7dSPeter Dunlap 		binary_array = kmem_alloc(value_length, KM_NOSLEEP);
519a6d42e7dSPeter Dunlap 		if (binary_array == NULL) {
520a6d42e7dSPeter Dunlap 			return (ENOMEM);
521a6d42e7dSPeter Dunlap 		}
522a6d42e7dSPeter Dunlap 
523a6d42e7dSPeter Dunlap 		if (iscsi_base64_str_to_binary(value, value_length,
524a6d42e7dSPeter Dunlap 		    binary_array, value_length, &binary_length) != 0) {
525a6d42e7dSPeter Dunlap 			kmem_free(binary_array, value_length);
526a6d42e7dSPeter Dunlap 			return (EINVAL);
527a6d42e7dSPeter Dunlap 		}
528a6d42e7dSPeter Dunlap 
529a6d42e7dSPeter Dunlap 		rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name,
530a6d42e7dSPeter Dunlap 		    binary_array, binary_length);
531a6d42e7dSPeter Dunlap 
532a6d42e7dSPeter Dunlap 		kmem_free(binary_array, value_length);
533a6d42e7dSPeter Dunlap 
534a6d42e7dSPeter Dunlap 		return (rc);
535a6d42e7dSPeter Dunlap 	} else {
536a6d42e7dSPeter Dunlap 		/*
537a6d42e7dSPeter Dunlap 		 * Decimal value (not permitted for "large-binary_value" so
538a6d42e7dSPeter Dunlap 		 * it must be smaller than 64 bits.  It's not really
539a6d42e7dSPeter Dunlap 		 * clear from the RFC what a decimal-binary-value might
540a6d42e7dSPeter Dunlap 		 * represent but presumably it should be treated the same
541a6d42e7dSPeter Dunlap 		 * as a hex or base64 value.  Therefore we'll convert it
542a6d42e7dSPeter Dunlap 		 * to an array of bytes.
543a6d42e7dSPeter Dunlap 		 */
5442ef9abdcSjv 		if ((rc = ddi_strtoull(value, NULL, 0,
545a6d42e7dSPeter Dunlap 		    (u_longlong_t *)&uint64_value)) != 0)
546a6d42e7dSPeter Dunlap 			return (rc);
547a6d42e7dSPeter Dunlap 
548a6d42e7dSPeter Dunlap 		rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name,
549a6d42e7dSPeter Dunlap 		    (uint8_t *)&uint64_value, sizeof (uint64_value));
550a6d42e7dSPeter Dunlap 
551a6d42e7dSPeter Dunlap 		return (rc);
552a6d42e7dSPeter Dunlap 	}
553a6d42e7dSPeter Dunlap 
554a6d42e7dSPeter Dunlap 	/* NOTREACHED */
555a6d42e7dSPeter Dunlap }
556a6d42e7dSPeter Dunlap 
557a6d42e7dSPeter Dunlap 
558a6d42e7dSPeter Dunlap static int
idm_nvlist_add_large_numerical(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)559a6d42e7dSPeter Dunlap idm_nvlist_add_large_numerical(nvlist_t *nvl,
560a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value)
561a6d42e7dSPeter Dunlap {
562a6d42e7dSPeter Dunlap 	/*
563a6d42e7dSPeter Dunlap 	 * A "large numerical" value can be larger than 64-bits.  Since
564a6d42e7dSPeter Dunlap 	 * there is no upper bound on the size of the value, we will
565a6d42e7dSPeter Dunlap 	 * punt and store it in string form.  We could also potentially
566a6d42e7dSPeter Dunlap 	 * treat the value as binary data.
567a6d42e7dSPeter Dunlap 	 */
568a6d42e7dSPeter Dunlap 	return (nvlist_add_string(nvl, ikvx->ik_key_name, value));
569a6d42e7dSPeter Dunlap }
570a6d42e7dSPeter Dunlap 
571a6d42e7dSPeter Dunlap 
572a6d42e7dSPeter Dunlap static int
idm_nvlist_add_numerical(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value)573a6d42e7dSPeter Dunlap idm_nvlist_add_numerical(nvlist_t *nvl,
574a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value)
575a6d42e7dSPeter Dunlap {
576a6d42e7dSPeter Dunlap 	int rc;
577a6d42e7dSPeter Dunlap 	uint64_t uint64_value;
578a6d42e7dSPeter Dunlap 
579a6d42e7dSPeter Dunlap 	/*
580a6d42e7dSPeter Dunlap 	 * "Numerical" values in the iSCSI standard are up to 64-bits wide.
581a6d42e7dSPeter Dunlap 	 * On a 32-bit system we could see an overflow here during conversion.
582a6d42e7dSPeter Dunlap 	 * This shouldn't happen with real-world values for the current
583a6d42e7dSPeter Dunlap 	 * iSCSI parameters of "numerical" type.
584a6d42e7dSPeter Dunlap 	 */
5852ef9abdcSjv 	rc = ddi_strtoull(value, NULL, 0, (u_longlong_t *)&uint64_value);
586a6d42e7dSPeter Dunlap 	if (rc == 0) {
587a6d42e7dSPeter Dunlap 		rc = nvlist_add_uint64(nvl, ikvx->ik_key_name, uint64_value);
588a6d42e7dSPeter Dunlap 	}
589a6d42e7dSPeter Dunlap 
590a6d42e7dSPeter Dunlap 	return (rc);
591a6d42e7dSPeter Dunlap }
592a6d42e7dSPeter Dunlap 
593a6d42e7dSPeter Dunlap 
594a6d42e7dSPeter Dunlap static int
idm_nvlist_add_numeric_range(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * range)595a6d42e7dSPeter Dunlap idm_nvlist_add_numeric_range(nvlist_t *nvl,
596a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *range)
597a6d42e7dSPeter Dunlap {
598a6d42e7dSPeter Dunlap 	nvlist_t *range_nvl;
599a6d42e7dSPeter Dunlap 	char *val_scan = range;
600a6d42e7dSPeter Dunlap 	uint64_t start_val, end_val;
601a6d42e7dSPeter Dunlap 	int val_len, range_len;
602a6d42e7dSPeter Dunlap 	int rc;
603a6d42e7dSPeter Dunlap 
604a6d42e7dSPeter Dunlap 	/* We'll store the range an an nvlist with two values */
605a6d42e7dSPeter Dunlap 	rc = nvlist_alloc(&range_nvl, NV_UNIQUE_NAME, KM_NOSLEEP);
606a6d42e7dSPeter Dunlap 	if (rc != 0) {
607a6d42e7dSPeter Dunlap 		return (rc);
608a6d42e7dSPeter Dunlap 	}
609a6d42e7dSPeter Dunlap 
610a6d42e7dSPeter Dunlap 	/*
611a6d42e7dSPeter Dunlap 	 * We expect idm_keyvalue_get_next to ensure the string is
612a6d42e7dSPeter Dunlap 	 * terminated
613a6d42e7dSPeter Dunlap 	 */
614a6d42e7dSPeter Dunlap 	range_len = strlen(range);
615a6d42e7dSPeter Dunlap 
616a6d42e7dSPeter Dunlap 	/*
617a6d42e7dSPeter Dunlap 	 * Find range separator
618a6d42e7dSPeter Dunlap 	 */
619a6d42e7dSPeter Dunlap 	val_len = idm_strcspn(val_scan, "~");
620a6d42e7dSPeter Dunlap 
621a6d42e7dSPeter Dunlap 	if (val_len == range_len) {
622a6d42e7dSPeter Dunlap 		/* invalid range */
623a6d42e7dSPeter Dunlap 		nvlist_free(range_nvl);
624a6d42e7dSPeter Dunlap 		return (EINVAL);
625a6d42e7dSPeter Dunlap 	}
626a6d42e7dSPeter Dunlap 
627a6d42e7dSPeter Dunlap 	/*
628a6d42e7dSPeter Dunlap 	 * Start value
629a6d42e7dSPeter Dunlap 	 */
630a6d42e7dSPeter Dunlap 	*(val_scan + val_len + 1) = '\0';
6312ef9abdcSjv 	rc = ddi_strtoull(val_scan, NULL, 0, (u_longlong_t *)&start_val);
632a6d42e7dSPeter Dunlap 	if (rc == 0) {
633a6d42e7dSPeter Dunlap 		rc = nvlist_add_uint64(range_nvl, "start", start_val);
634a6d42e7dSPeter Dunlap 	}
635a6d42e7dSPeter Dunlap 	if (rc != 0) {
636a6d42e7dSPeter Dunlap 		nvlist_free(range_nvl);
637a6d42e7dSPeter Dunlap 		return (rc);
638a6d42e7dSPeter Dunlap 	}
639a6d42e7dSPeter Dunlap 
640a6d42e7dSPeter Dunlap 	/*
641a6d42e7dSPeter Dunlap 	 * End value
642a6d42e7dSPeter Dunlap 	 */
643a6d42e7dSPeter Dunlap 	val_scan += val_len + 1;
6442ef9abdcSjv 	rc = ddi_strtoull(val_scan, NULL, 0, (u_longlong_t *)&end_val);
645a6d42e7dSPeter Dunlap 	if (rc == 0) {
646a6d42e7dSPeter Dunlap 		rc = nvlist_add_uint64(range_nvl, "start", end_val);
647a6d42e7dSPeter Dunlap 	}
648a6d42e7dSPeter Dunlap 	if (rc != 0) {
649a6d42e7dSPeter Dunlap 		nvlist_free(range_nvl);
650a6d42e7dSPeter Dunlap 		return (rc);
651a6d42e7dSPeter Dunlap 	}
652a6d42e7dSPeter Dunlap 
653a6d42e7dSPeter Dunlap 	/*
654a6d42e7dSPeter Dunlap 	 * Now add the "range" nvlist to the main nvlist
655a6d42e7dSPeter Dunlap 	 */
656a6d42e7dSPeter Dunlap 	rc = nvlist_add_nvlist(nvl, ikvx->ik_key_name, range_nvl);
657a6d42e7dSPeter Dunlap 	if (rc != 0) {
658a6d42e7dSPeter Dunlap 		nvlist_free(range_nvl);
659a6d42e7dSPeter Dunlap 		return (rc);
660a6d42e7dSPeter Dunlap 	}
661a6d42e7dSPeter Dunlap 
662a6d42e7dSPeter Dunlap 	nvlist_free(range_nvl);
663a6d42e7dSPeter Dunlap 	return (0);
664a6d42e7dSPeter Dunlap }
665a6d42e7dSPeter Dunlap 
666a6d42e7dSPeter Dunlap 
667a6d42e7dSPeter Dunlap static int
idm_nvlist_add_list_of_values(nvlist_t * nvl,const idm_kv_xlate_t * ikvx,char * value_list)668a6d42e7dSPeter Dunlap idm_nvlist_add_list_of_values(nvlist_t *nvl,
669a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, char *value_list)
670a6d42e7dSPeter Dunlap {
671a6d42e7dSPeter Dunlap 	char value_name[8];
672a6d42e7dSPeter Dunlap 	nvlist_t *value_list_nvl;
673a6d42e7dSPeter Dunlap 	char *val_scan = value_list;
674a6d42e7dSPeter Dunlap 	int value_index = 0;
675a6d42e7dSPeter Dunlap 	int val_len, val_list_len;
676a6d42e7dSPeter Dunlap 	int rc;
677a6d42e7dSPeter Dunlap 
678a6d42e7dSPeter Dunlap 	rc = nvlist_alloc(&value_list_nvl, NV_UNIQUE_NAME, KM_NOSLEEP);
679a6d42e7dSPeter Dunlap 	if (rc != 0) {
680a6d42e7dSPeter Dunlap 		return (rc);
681a6d42e7dSPeter Dunlap 	}
682a6d42e7dSPeter Dunlap 
683a6d42e7dSPeter Dunlap 	/*
684a6d42e7dSPeter Dunlap 	 * We expect idm_keyvalue_get_next to ensure the string is
685a6d42e7dSPeter Dunlap 	 * terminated
686a6d42e7dSPeter Dunlap 	 */
687a6d42e7dSPeter Dunlap 	val_list_len = strlen(value_list);
688a6d42e7dSPeter Dunlap 	if (val_list_len == 0) {
689a6d42e7dSPeter Dunlap 		nvlist_free(value_list_nvl);
690a6d42e7dSPeter Dunlap 		return (EINVAL);
691a6d42e7dSPeter Dunlap 	}
692a6d42e7dSPeter Dunlap 
693a6d42e7dSPeter Dunlap 	for (;;) {
694a6d42e7dSPeter Dunlap 		(void) snprintf(value_name, 8, "value%d", value_index);
695a6d42e7dSPeter Dunlap 
696a6d42e7dSPeter Dunlap 		val_len = idm_strcspn(val_scan, ",");
697a6d42e7dSPeter Dunlap 
698a6d42e7dSPeter Dunlap 		if (*(val_scan + val_len) != '\0') {
699a6d42e7dSPeter Dunlap 			*(val_scan + val_len) = '\0';
700a6d42e7dSPeter Dunlap 		}
701a6d42e7dSPeter Dunlap 		rc = nvlist_add_string(value_list_nvl, value_name, val_scan);
702a6d42e7dSPeter Dunlap 		if (rc != 0) {
703a6d42e7dSPeter Dunlap 			nvlist_free(value_list_nvl);
704a6d42e7dSPeter Dunlap 			return (rc);
705a6d42e7dSPeter Dunlap 		}
706a6d42e7dSPeter Dunlap 
707a6d42e7dSPeter Dunlap 		/*
708a6d42e7dSPeter Dunlap 		 * Move to next value, see if we're at the end of the value
709a6d42e7dSPeter Dunlap 		 * list
710a6d42e7dSPeter Dunlap 		 */
711a6d42e7dSPeter Dunlap 		val_scan += val_len + 1;
712a6d42e7dSPeter Dunlap 		if (val_scan == value_list + val_list_len + 1) {
713a6d42e7dSPeter Dunlap 			break;
714a6d42e7dSPeter Dunlap 		}
715a6d42e7dSPeter Dunlap 
716a6d42e7dSPeter Dunlap 		value_index++;
717a6d42e7dSPeter Dunlap 	}
718a6d42e7dSPeter Dunlap 
719a6d42e7dSPeter Dunlap 	rc = nvlist_add_nvlist(nvl, ikvx->ik_key_name, value_list_nvl);
720a6d42e7dSPeter Dunlap 	if (rc != 0) {
721a6d42e7dSPeter Dunlap 		nvlist_free(value_list_nvl);
722a6d42e7dSPeter Dunlap 		return (rc);
723a6d42e7dSPeter Dunlap 	}
724a6d42e7dSPeter Dunlap 
725a6d42e7dSPeter Dunlap 	nvlist_free(value_list_nvl);
726a6d42e7dSPeter Dunlap 	return (0);
727a6d42e7dSPeter Dunlap }
728a6d42e7dSPeter Dunlap 
729a6d42e7dSPeter Dunlap /*
730a6d42e7dSPeter Dunlap  * Convert an nvlist containing standard iSCSI key names and values into
731a6d42e7dSPeter Dunlap  * a text buffer with properly formatted iSCSI key-value pairs ready to
732a6d42e7dSPeter Dunlap  * transmit on the wire.  *textbuf should be NULL and will be set to point
733a6d42e7dSPeter Dunlap  * the resulting text buffer.
734a6d42e7dSPeter Dunlap  */
735a6d42e7dSPeter Dunlap 
736a6d42e7dSPeter Dunlap int
idm_nvlist_to_textbuf(nvlist_t * nvl,char ** textbuf,int * textbuflen,int * validlen)737a6d42e7dSPeter Dunlap idm_nvlist_to_textbuf(nvlist_t *nvl, char **textbuf, int *textbuflen,
738*2fcabb59SToomas Soome     int *validlen)
739a6d42e7dSPeter Dunlap {
740a6d42e7dSPeter Dunlap 	int rc = 0;
741a6d42e7dSPeter Dunlap 	nvpair_t *nvp = NULL;
742a6d42e7dSPeter Dunlap 	idm_textbuf_t itb;
743a6d42e7dSPeter Dunlap 
744a6d42e7dSPeter Dunlap 	bzero(&itb, sizeof (itb));
745a6d42e7dSPeter Dunlap 
746a6d42e7dSPeter Dunlap 	for (;;) {
747a6d42e7dSPeter Dunlap 		nvp = nvlist_next_nvpair(nvl, nvp);
748a6d42e7dSPeter Dunlap 
749a6d42e7dSPeter Dunlap 		if (nvp == NULL) {
750a6d42e7dSPeter Dunlap 			/* Last nvpair in nvlist, we're done */
751a6d42e7dSPeter Dunlap 			break;
752a6d42e7dSPeter Dunlap 		}
753a6d42e7dSPeter Dunlap 
754a6d42e7dSPeter Dunlap 		if ((rc = idm_itextbuf_add_nvpair(nvp, &itb)) != 0) {
755a6d42e7dSPeter Dunlap 			/* There was a problem building the key/value pair */
756a6d42e7dSPeter Dunlap 			break;
757a6d42e7dSPeter Dunlap 		}
758a6d42e7dSPeter Dunlap 	}
759a6d42e7dSPeter Dunlap 
760a6d42e7dSPeter Dunlap 	*textbuf = itb.itb_mem;
761a6d42e7dSPeter Dunlap 	*textbuflen = itb.itb_mem_len;
762a6d42e7dSPeter Dunlap 	*validlen = itb.itb_offset;
763a6d42e7dSPeter Dunlap 
764a6d42e7dSPeter Dunlap 	return (rc);
765a6d42e7dSPeter Dunlap }
766a6d42e7dSPeter Dunlap 
767a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_nvpair(nvpair_t * nvp,idm_textbuf_t * itb)768a6d42e7dSPeter Dunlap idm_itextbuf_add_nvpair(nvpair_t *nvp,
769a6d42e7dSPeter Dunlap     idm_textbuf_t *itb)
770a6d42e7dSPeter Dunlap {
771a6d42e7dSPeter Dunlap 	int rc = 0;
772a6d42e7dSPeter Dunlap 	char *key;
773a6d42e7dSPeter Dunlap 	const idm_kv_xlate_t *ikvx;
774a6d42e7dSPeter Dunlap 
775a6d42e7dSPeter Dunlap 	key = nvpair_name(nvp);
776a6d42e7dSPeter Dunlap 
777a6d42e7dSPeter Dunlap 	ikvx = idm_lookup_kv_xlate(key, strlen(key));
778a6d42e7dSPeter Dunlap 
779a6d42e7dSPeter Dunlap 	/*
780a6d42e7dSPeter Dunlap 	 * Any key supplied by the initiator that is not in our table
781a6d42e7dSPeter Dunlap 	 * will be responded to with the string value "NotUnderstood".
782a6d42e7dSPeter Dunlap 	 * An example is a vendor specific key.
783a6d42e7dSPeter Dunlap 	 */
784a6d42e7dSPeter Dunlap 	ASSERT((ikvx->ik_key_id != KI_MAX_KEY) ||
785a6d42e7dSPeter Dunlap 	    (nvpair_type(nvp) == DATA_TYPE_STRING));
786a6d42e7dSPeter Dunlap 
787a6d42e7dSPeter Dunlap 	/*
788a6d42e7dSPeter Dunlap 	 * Look for a matching key value in the key/value pair table.
789a6d42e7dSPeter Dunlap 	 * The matching entry in the table will tell us how to encode
790a6d42e7dSPeter Dunlap 	 * the key and value in the nvlist.
791a6d42e7dSPeter Dunlap 	 */
792a6d42e7dSPeter Dunlap 	switch (ikvx->ik_idm_type) {
793a6d42e7dSPeter Dunlap 	case KT_TEXT:
794a6d42e7dSPeter Dunlap 	case KT_SIMPLE:
795a6d42e7dSPeter Dunlap 	case KT_ISCSI_NAME:
796a6d42e7dSPeter Dunlap 	case KT_ISCSI_LOCAL_NAME:
797a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_string(nvp, ikvx, itb);
798a6d42e7dSPeter Dunlap 		break;
799a6d42e7dSPeter Dunlap 	case KT_BOOLEAN:
800a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_boolean(nvp, ikvx, itb);
801a6d42e7dSPeter Dunlap 		break;
802a6d42e7dSPeter Dunlap 	case KT_REGULAR_BINARY:
803a6d42e7dSPeter Dunlap 	case KT_LARGE_BINARY:
804a6d42e7dSPeter Dunlap 	case KT_BINARY:
805a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_binary(nvp, ikvx, itb);
806a6d42e7dSPeter Dunlap 		break;
807a6d42e7dSPeter Dunlap 	case KT_LARGE_NUMERICAL:
808a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_large_numerical(nvp, ikvx, itb);
809a6d42e7dSPeter Dunlap 		break;
810a6d42e7dSPeter Dunlap 	case KT_NUMERICAL:
811a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_numerical(nvp, ikvx, itb);
812a6d42e7dSPeter Dunlap 		break;
813a6d42e7dSPeter Dunlap 	case KT_NUMERIC_RANGE:
814a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_numeric_range(nvp, ikvx, itb);
815a6d42e7dSPeter Dunlap 		break;
816a6d42e7dSPeter Dunlap 	case KT_LIST_OF_VALUES:
817a6d42e7dSPeter Dunlap 		rc = idm_itextbuf_add_list_of_values(nvp, ikvx, itb);
818a6d42e7dSPeter Dunlap 		break;
819a6d42e7dSPeter Dunlap 	default:
820a6d42e7dSPeter Dunlap 		ASSERT(0); /* This should never happen */
821a6d42e7dSPeter Dunlap 		break;
822a6d42e7dSPeter Dunlap 	}
823a6d42e7dSPeter Dunlap 
824a6d42e7dSPeter Dunlap 	return (rc);
825a6d42e7dSPeter Dunlap }
826a6d42e7dSPeter Dunlap 
827a6d42e7dSPeter Dunlap /* ARGSUSED */
828a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_string(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)829a6d42e7dSPeter Dunlap idm_itextbuf_add_string(nvpair_t *nvp,
830a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
831a6d42e7dSPeter Dunlap {
832a6d42e7dSPeter Dunlap 	char	*key_name;
833a6d42e7dSPeter Dunlap 	char	*value;
834a6d42e7dSPeter Dunlap 	int	rc;
835a6d42e7dSPeter Dunlap 
836a6d42e7dSPeter Dunlap 	/* Start with the key name */
837a6d42e7dSPeter Dunlap 	key_name = nvpair_name(nvp);
838a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, key_name);
839a6d42e7dSPeter Dunlap 
840a6d42e7dSPeter Dunlap 	/* Add separator */
841a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '=');
842a6d42e7dSPeter Dunlap 
843a6d42e7dSPeter Dunlap 	/* Add value */
844a6d42e7dSPeter Dunlap 	rc = nvpair_value_string(nvp, &value);
845a6d42e7dSPeter Dunlap 	ASSERT(rc == 0);
846a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, value);
847a6d42e7dSPeter Dunlap 
848a6d42e7dSPeter Dunlap 	/* Add trailing 0x00 */
849a6d42e7dSPeter Dunlap 	textbuf_terminate_kvpair(itb);
850a6d42e7dSPeter Dunlap 
851a6d42e7dSPeter Dunlap 	return (0);
852a6d42e7dSPeter Dunlap }
853a6d42e7dSPeter Dunlap 
854a6d42e7dSPeter Dunlap 
855a6d42e7dSPeter Dunlap /* ARGSUSED */
856a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_boolean(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)857a6d42e7dSPeter Dunlap idm_itextbuf_add_boolean(nvpair_t *nvp,
858a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
859a6d42e7dSPeter Dunlap {
860a6d42e7dSPeter Dunlap 	char		*key_name;
861a6d42e7dSPeter Dunlap 	boolean_t	value;
862a6d42e7dSPeter Dunlap 	int	rc;
863a6d42e7dSPeter Dunlap 
864a6d42e7dSPeter Dunlap 	/* Start with the key name */
865a6d42e7dSPeter Dunlap 	key_name = nvpair_name(nvp);
866a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, key_name);
867a6d42e7dSPeter Dunlap 
868a6d42e7dSPeter Dunlap 	/* Add separator */
869a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '=');
870a6d42e7dSPeter Dunlap 
871a6d42e7dSPeter Dunlap 	/* Add value */
872a6d42e7dSPeter Dunlap 	rc = nvpair_value_boolean_value(nvp, &value);
873a6d42e7dSPeter Dunlap 	ASSERT(rc == 0);
874a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, value ? "Yes" : "No");
875a6d42e7dSPeter Dunlap 
876a6d42e7dSPeter Dunlap 	/* Add trailing 0x00 */
877a6d42e7dSPeter Dunlap 	textbuf_terminate_kvpair(itb);
878a6d42e7dSPeter Dunlap 
879a6d42e7dSPeter Dunlap 	return (0);
880a6d42e7dSPeter Dunlap }
881a6d42e7dSPeter Dunlap 
882a6d42e7dSPeter Dunlap /* ARGSUSED */
883a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_binary(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)884a6d42e7dSPeter Dunlap idm_itextbuf_add_binary(nvpair_t *nvp,
885a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
886a6d42e7dSPeter Dunlap {
887a6d42e7dSPeter Dunlap 	char		*key_name;
888a6d42e7dSPeter Dunlap 	unsigned char	*value;
889a6d42e7dSPeter Dunlap 	unsigned int	len;
890a6d42e7dSPeter Dunlap 	unsigned long	n;
891a6d42e7dSPeter Dunlap 	int	rc;
892a6d42e7dSPeter Dunlap 
893a6d42e7dSPeter Dunlap 	/* Start with the key name */
894a6d42e7dSPeter Dunlap 	key_name = nvpair_name(nvp);
895a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, key_name);
896a6d42e7dSPeter Dunlap 
897a6d42e7dSPeter Dunlap 	/* Add separator */
898a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '=');
899a6d42e7dSPeter Dunlap 
900a6d42e7dSPeter Dunlap 	/* Add value */
901a6d42e7dSPeter Dunlap 	rc = nvpair_value_byte_array(nvp, &value, &len);
902a6d42e7dSPeter Dunlap 	ASSERT(rc == 0);
903a6d42e7dSPeter Dunlap 
904a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, "0x");
905a6d42e7dSPeter Dunlap 
906a6d42e7dSPeter Dunlap 	while (len > 0) {
907a6d42e7dSPeter Dunlap 		n = *value++;
908a6d42e7dSPeter Dunlap 		len--;
909a6d42e7dSPeter Dunlap 
910a6d42e7dSPeter Dunlap 		textbuf_append_char(itb, idm_hex_to_ascii[(n >> 4) & 0xf]);
911a6d42e7dSPeter Dunlap 		textbuf_append_char(itb, idm_hex_to_ascii[n & 0xf]);
912a6d42e7dSPeter Dunlap 	}
913a6d42e7dSPeter Dunlap 
914a6d42e7dSPeter Dunlap 	/* Add trailing 0x00 */
915a6d42e7dSPeter Dunlap 	textbuf_terminate_kvpair(itb);
916a6d42e7dSPeter Dunlap 
917a6d42e7dSPeter Dunlap 	return (0);
918a6d42e7dSPeter Dunlap }
919a6d42e7dSPeter Dunlap 
920a6d42e7dSPeter Dunlap /* ARGSUSED */
921a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_large_numerical(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)922a6d42e7dSPeter Dunlap idm_itextbuf_add_large_numerical(nvpair_t *nvp,
923a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
924a6d42e7dSPeter Dunlap {
925a6d42e7dSPeter Dunlap 	ASSERT(0);
926a6d42e7dSPeter Dunlap 	return (0);
927a6d42e7dSPeter Dunlap }
928a6d42e7dSPeter Dunlap 
929a6d42e7dSPeter Dunlap /* ARGSUSED */
930a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_numerical(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)931a6d42e7dSPeter Dunlap idm_itextbuf_add_numerical(nvpair_t *nvp,
932a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
933a6d42e7dSPeter Dunlap {
934a6d42e7dSPeter Dunlap 	char		*key_name;
935a6d42e7dSPeter Dunlap 	uint64_t	value;
936a6d42e7dSPeter Dunlap 	int	rc;
937a6d42e7dSPeter Dunlap 	char		str[16];
938a6d42e7dSPeter Dunlap 
939a6d42e7dSPeter Dunlap 	/* Start with the key name */
940a6d42e7dSPeter Dunlap 	key_name = nvpair_name(nvp);
941a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, key_name);
942a6d42e7dSPeter Dunlap 
943a6d42e7dSPeter Dunlap 	/* Add separator */
944a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '=');
945a6d42e7dSPeter Dunlap 
946a6d42e7dSPeter Dunlap 	/* Add value */
947a6d42e7dSPeter Dunlap 	rc = nvpair_value_uint64(nvp, &value);
948a6d42e7dSPeter Dunlap 	ASSERT(rc == 0);
949a6d42e7dSPeter Dunlap 	(void) sprintf(str, "%llu", (u_longlong_t)value);
950a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, str);
951a6d42e7dSPeter Dunlap 
952a6d42e7dSPeter Dunlap 	/* Add trailing 0x00 */
953a6d42e7dSPeter Dunlap 	textbuf_terminate_kvpair(itb);
954a6d42e7dSPeter Dunlap 
955a6d42e7dSPeter Dunlap 	return (0);
956a6d42e7dSPeter Dunlap }
957a6d42e7dSPeter Dunlap 
958a6d42e7dSPeter Dunlap /* ARGSUSED */
959a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_numeric_range(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)960a6d42e7dSPeter Dunlap idm_itextbuf_add_numeric_range(nvpair_t *nvp,
961a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
962a6d42e7dSPeter Dunlap {
963a6d42e7dSPeter Dunlap 	ASSERT(0);
964a6d42e7dSPeter Dunlap 	return (0);
965a6d42e7dSPeter Dunlap }
966a6d42e7dSPeter Dunlap 
967a6d42e7dSPeter Dunlap /* ARGSUSED */
968a6d42e7dSPeter Dunlap static int
idm_itextbuf_add_list_of_values(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,idm_textbuf_t * itb)969a6d42e7dSPeter Dunlap idm_itextbuf_add_list_of_values(nvpair_t *nvp,
970a6d42e7dSPeter Dunlap     const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb)
971a6d42e7dSPeter Dunlap {
972a6d42e7dSPeter Dunlap 	char		*key_name;
973a6d42e7dSPeter Dunlap 	nvpair_t	*vchoice = NULL;
974a6d42e7dSPeter Dunlap 	char		*vchoice_string = NULL;
975a6d42e7dSPeter Dunlap 	int		rc;
976a6d42e7dSPeter Dunlap 
977a6d42e7dSPeter Dunlap 	/* Start with the key name */
978a6d42e7dSPeter Dunlap 	key_name = nvpair_name(nvp);
979a6d42e7dSPeter Dunlap 	textbuf_strcpy(itb, key_name);
980a6d42e7dSPeter Dunlap 
981a6d42e7dSPeter Dunlap 	/* Add separator */
982a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '=');
983a6d42e7dSPeter Dunlap 
984a6d42e7dSPeter Dunlap 	/* Add value choices */
985a6d42e7dSPeter Dunlap 	vchoice = idm_get_next_listvalue(nvp, NULL);
986a6d42e7dSPeter Dunlap 	while (vchoice != NULL) {
987a6d42e7dSPeter Dunlap 		rc = nvpair_value_string(vchoice, &vchoice_string);
988a6d42e7dSPeter Dunlap 		ASSERT(rc == 0);
989a6d42e7dSPeter Dunlap 		textbuf_strcpy(itb, vchoice_string);
990a6d42e7dSPeter Dunlap 		vchoice = idm_get_next_listvalue(nvp, vchoice);
991a6d42e7dSPeter Dunlap 		if (vchoice != NULL) {
992a6d42e7dSPeter Dunlap 			/* Add ',' between choices */
993a6d42e7dSPeter Dunlap 			textbuf_append_char(itb, ',');
994a6d42e7dSPeter Dunlap 		}
995a6d42e7dSPeter Dunlap 	}
996a6d42e7dSPeter Dunlap 
997a6d42e7dSPeter Dunlap 	/* Add trailing 0x00 */
998a6d42e7dSPeter Dunlap 	textbuf_terminate_kvpair(itb);
999a6d42e7dSPeter Dunlap 
1000a6d42e7dSPeter Dunlap 	return (0);
1001a6d42e7dSPeter Dunlap }
1002a6d42e7dSPeter Dunlap 
1003a6d42e7dSPeter Dunlap 
1004a6d42e7dSPeter Dunlap static void
textbuf_makeroom(idm_textbuf_t * itb,int size)1005a6d42e7dSPeter Dunlap textbuf_makeroom(idm_textbuf_t *itb, int size)
1006a6d42e7dSPeter Dunlap {
1007a6d42e7dSPeter Dunlap 	char	*new_mem;
1008a6d42e7dSPeter Dunlap 	int	new_mem_len;
1009a6d42e7dSPeter Dunlap 
1010a6d42e7dSPeter Dunlap 	if (itb->itb_mem == NULL) {
1011a6d42e7dSPeter Dunlap 		itb->itb_mem_len = MAX(TEXTBUF_CHUNKSIZE, size);
1012a6d42e7dSPeter Dunlap 		itb->itb_mem = kmem_alloc(itb->itb_mem_len, KM_SLEEP);
1013a6d42e7dSPeter Dunlap 	} else if ((itb->itb_offset + size) > itb->itb_mem_len) {
1014a6d42e7dSPeter Dunlap 		new_mem_len = itb->itb_mem_len + MAX(TEXTBUF_CHUNKSIZE, size);
1015a6d42e7dSPeter Dunlap 		new_mem = kmem_alloc(new_mem_len, KM_SLEEP);
1016a6d42e7dSPeter Dunlap 		bcopy(itb->itb_mem, new_mem, itb->itb_mem_len);
1017a6d42e7dSPeter Dunlap 		kmem_free(itb->itb_mem, itb->itb_mem_len);
1018a6d42e7dSPeter Dunlap 		itb->itb_mem = new_mem;
1019a6d42e7dSPeter Dunlap 		itb->itb_mem_len = new_mem_len;
1020a6d42e7dSPeter Dunlap 	}
1021a6d42e7dSPeter Dunlap }
1022a6d42e7dSPeter Dunlap 
1023a6d42e7dSPeter Dunlap static void
textbuf_memcpy(idm_textbuf_t * itb,void * mem,int mem_len)1024a6d42e7dSPeter Dunlap textbuf_memcpy(idm_textbuf_t *itb, void *mem, int mem_len)
1025a6d42e7dSPeter Dunlap {
1026a6d42e7dSPeter Dunlap 	textbuf_makeroom(itb, mem_len);
1027a6d42e7dSPeter Dunlap 	(void) memcpy(itb->itb_mem + itb->itb_offset, mem, mem_len);
1028a6d42e7dSPeter Dunlap 	itb->itb_offset += mem_len;
1029a6d42e7dSPeter Dunlap }
1030a6d42e7dSPeter Dunlap 
1031a6d42e7dSPeter Dunlap static void
textbuf_strcpy(idm_textbuf_t * itb,char * str)1032a6d42e7dSPeter Dunlap textbuf_strcpy(idm_textbuf_t *itb, char *str)
1033a6d42e7dSPeter Dunlap {
1034a6d42e7dSPeter Dunlap 	textbuf_memcpy(itb, str, strlen(str));
1035a6d42e7dSPeter Dunlap }
1036a6d42e7dSPeter Dunlap 
1037a6d42e7dSPeter Dunlap static void
textbuf_append_char(idm_textbuf_t * itb,char c)1038a6d42e7dSPeter Dunlap textbuf_append_char(idm_textbuf_t *itb, char c)
1039a6d42e7dSPeter Dunlap {
1040a6d42e7dSPeter Dunlap 	textbuf_makeroom(itb, sizeof (char));
1041a6d42e7dSPeter Dunlap 	*(itb->itb_mem + itb->itb_offset) = c;
1042a6d42e7dSPeter Dunlap 	itb->itb_offset++;
1043a6d42e7dSPeter Dunlap }
1044a6d42e7dSPeter Dunlap 
1045a6d42e7dSPeter Dunlap static void
textbuf_terminate_kvpair(idm_textbuf_t * itb)1046a6d42e7dSPeter Dunlap textbuf_terminate_kvpair(idm_textbuf_t *itb)
1047a6d42e7dSPeter Dunlap {
1048a6d42e7dSPeter Dunlap 	textbuf_append_char(itb, '\0');
1049a6d42e7dSPeter Dunlap }
1050a6d42e7dSPeter Dunlap 
1051a6d42e7dSPeter Dunlap static int
idm_ascii_to_hex(char * enc_hex_byte,uint8_t * bin_val)1052a6d42e7dSPeter Dunlap idm_ascii_to_hex(char *enc_hex_byte, uint8_t *bin_val)
1053a6d42e7dSPeter Dunlap {
1054a6d42e7dSPeter Dunlap 	uint8_t nibble1, nibble2;
1055a6d42e7dSPeter Dunlap 	char enc_char = *enc_hex_byte;
1056a6d42e7dSPeter Dunlap 
1057a6d42e7dSPeter Dunlap 	if (enc_char >= '0' && enc_char <= '9') {
1058a6d42e7dSPeter Dunlap 		nibble1 = (enc_char - '0');
1059a6d42e7dSPeter Dunlap 	} else if (enc_char >= 'A' && enc_char <= 'F') {
1060a6d42e7dSPeter Dunlap 		nibble1 = (0xA + (enc_char - 'A'));
1061a6d42e7dSPeter Dunlap 	} else if (enc_char >= 'a' && enc_char <= 'f') {
1062a6d42e7dSPeter Dunlap 		nibble1 = (0xA + (enc_char - 'a'));
1063a6d42e7dSPeter Dunlap 	} else {
1064a6d42e7dSPeter Dunlap 		return (EINVAL);
1065a6d42e7dSPeter Dunlap 	}
1066a6d42e7dSPeter Dunlap 
1067a6d42e7dSPeter Dunlap 	enc_hex_byte++;
1068a6d42e7dSPeter Dunlap 	enc_char = *enc_hex_byte;
1069a6d42e7dSPeter Dunlap 
1070a6d42e7dSPeter Dunlap 	if (enc_char >= '0' && enc_char <= '9') {
1071a6d42e7dSPeter Dunlap 		nibble2 = (enc_char - '0');
1072a6d42e7dSPeter Dunlap 	} else if (enc_char >= 'A' && enc_char <= 'F') {
1073a6d42e7dSPeter Dunlap 		nibble2 = (0xA + (enc_char - 'A'));
1074a6d42e7dSPeter Dunlap 	} else if (enc_char >= 'a' && enc_char <= 'f') {
1075a6d42e7dSPeter Dunlap 		nibble2 = (0xA + (enc_char - 'a'));
1076a6d42e7dSPeter Dunlap 	} else {
1077a6d42e7dSPeter Dunlap 		return (EINVAL);
1078a6d42e7dSPeter Dunlap 	}
1079a6d42e7dSPeter Dunlap 
1080a6d42e7dSPeter Dunlap 	*bin_val = (nibble1 << 4) | nibble2;
1081a6d42e7dSPeter Dunlap 
1082a6d42e7dSPeter Dunlap 	return (0);
1083a6d42e7dSPeter Dunlap }
1084a6d42e7dSPeter Dunlap 
1085a6d42e7dSPeter Dunlap 
idm_base16_str_to_binary(char * hstr,int hstr_len,uint8_t * binary_array,int binary_length)1086a6d42e7dSPeter Dunlap static int idm_base16_str_to_binary(char *hstr, int hstr_len,
1087a6d42e7dSPeter Dunlap     uint8_t *binary_array, int binary_length)
1088a6d42e7dSPeter Dunlap {
1089a6d42e7dSPeter Dunlap 	char	tmpstr[2];
1090a6d42e7dSPeter Dunlap 	uchar_t *binary_scan;
1091a6d42e7dSPeter Dunlap 
1092a6d42e7dSPeter Dunlap 	binary_scan = binary_array;
1093a6d42e7dSPeter Dunlap 
1094a6d42e7dSPeter Dunlap 	/*
1095a6d42e7dSPeter Dunlap 	 * If the length of the encoded ascii hex value is a multiple
1096a6d42e7dSPeter Dunlap 	 * of two then every two ascii characters correspond to a hex
1097a6d42e7dSPeter Dunlap 	 * byte.  If the length of the value is not a multiple of two
1098a6d42e7dSPeter Dunlap 	 * then the first character is the first hex byte and then for
1099a6d42e7dSPeter Dunlap 	 * the remaining of the string every two ascii characters
1100a6d42e7dSPeter Dunlap 	 * correspond to a hex byte
1101a6d42e7dSPeter Dunlap 	 */
1102a6d42e7dSPeter Dunlap 	if ((hstr_len % 2) != 0) {
1103a6d42e7dSPeter Dunlap 
1104a6d42e7dSPeter Dunlap 		tmpstr[0] = '0';
1105a6d42e7dSPeter Dunlap 		tmpstr[1] = *hstr;
1106a6d42e7dSPeter Dunlap 
1107a6d42e7dSPeter Dunlap 		if (idm_ascii_to_hex(tmpstr, binary_scan) != 0) {
1108a6d42e7dSPeter Dunlap 			return (EINVAL);
1109a6d42e7dSPeter Dunlap 		}
1110a6d42e7dSPeter Dunlap 
1111a6d42e7dSPeter Dunlap 		hstr++;
1112a6d42e7dSPeter Dunlap 		binary_scan++;
1113a6d42e7dSPeter Dunlap 	}
1114a6d42e7dSPeter Dunlap 
1115a6d42e7dSPeter Dunlap 	while (binary_scan != binary_array + binary_length) {
1116a6d42e7dSPeter Dunlap 		if (idm_ascii_to_hex(hstr, binary_scan) != 0) {
1117a6d42e7dSPeter Dunlap 			return (EINVAL);
1118a6d42e7dSPeter Dunlap 		}
1119a6d42e7dSPeter Dunlap 
1120a6d42e7dSPeter Dunlap 		hstr += 2;
1121a6d42e7dSPeter Dunlap 		binary_scan++;
1122a6d42e7dSPeter Dunlap 	}
1123a6d42e7dSPeter Dunlap 
1124a6d42e7dSPeter Dunlap 	return (0);
1125a6d42e7dSPeter Dunlap }
1126a6d42e7dSPeter Dunlap 
1127a6d42e7dSPeter Dunlap static size_t
idm_strnlen(const char * str,size_t maxlen)1128a6d42e7dSPeter Dunlap idm_strnlen(const char *str, size_t maxlen)
1129a6d42e7dSPeter Dunlap {
1130a6d42e7dSPeter Dunlap 	const char *ptr;
1131a6d42e7dSPeter Dunlap 
1132a6d42e7dSPeter Dunlap 	ptr = memchr(str, 0, maxlen);
1133a6d42e7dSPeter Dunlap 	if (ptr == NULL)
1134a6d42e7dSPeter Dunlap 		return (maxlen);
1135a6d42e7dSPeter Dunlap 
1136a6d42e7dSPeter Dunlap 	return ((uintptr_t)ptr - (uintptr_t)str);
1137a6d42e7dSPeter Dunlap }
1138a6d42e7dSPeter Dunlap 
1139a6d42e7dSPeter Dunlap 
1140a6d42e7dSPeter Dunlap size_t
idm_strcspn(const char * string,const char * charset)1141a6d42e7dSPeter Dunlap idm_strcspn(const char *string, const char *charset)
1142a6d42e7dSPeter Dunlap {
1143a6d42e7dSPeter Dunlap 	const char *p, *q;
1144a6d42e7dSPeter Dunlap 
1145a6d42e7dSPeter Dunlap 	for (q = string; *q != '\0'; ++q) {
1146a6d42e7dSPeter Dunlap 		for (p = charset; *p != '\0' && *p != *q; )
1147a6d42e7dSPeter Dunlap 			p++;
1148a6d42e7dSPeter Dunlap 		if (*p != '\0') {
1149a6d42e7dSPeter Dunlap 			break;
1150a6d42e7dSPeter Dunlap 		}
1151a6d42e7dSPeter Dunlap 	}
1152a6d42e7dSPeter Dunlap 	return ((uintptr_t)q - (uintptr_t)string);
1153a6d42e7dSPeter Dunlap }
1154a6d42e7dSPeter Dunlap 
1155a6d42e7dSPeter Dunlap /*
1156a6d42e7dSPeter Dunlap  * We allow a list of choices to be represented as a single nvpair
1157a6d42e7dSPeter Dunlap  * (list with one value choice), or as an nvlist with a single nvpair
1158a6d42e7dSPeter Dunlap  * (also a list with on value choice), or as an nvlist with multiple
1159a6d42e7dSPeter Dunlap  * nvpairs (a list with multiple value choices).  This function implements
1160a6d42e7dSPeter Dunlap  * the "get next" functionality regardless of the choice list structure.
1161a6d42e7dSPeter Dunlap  *
1162a6d42e7dSPeter Dunlap  * nvpair_t's that contain choices are always strings.
1163a6d42e7dSPeter Dunlap  */
1164a6d42e7dSPeter Dunlap nvpair_t *
idm_get_next_listvalue(nvpair_t * value_list,nvpair_t * curr_nvp)1165a6d42e7dSPeter Dunlap idm_get_next_listvalue(nvpair_t *value_list, nvpair_t *curr_nvp)
1166a6d42e7dSPeter Dunlap {
1167a6d42e7dSPeter Dunlap 	nvpair_t	*result;
1168a6d42e7dSPeter Dunlap 	nvlist_t	*nvl;
1169a6d42e7dSPeter Dunlap 	int		nvrc;
1170a6d42e7dSPeter Dunlap 	data_type_t	nvp_type;
1171a6d42e7dSPeter Dunlap 
1172a6d42e7dSPeter Dunlap 	nvp_type = nvpair_type(value_list);
1173a6d42e7dSPeter Dunlap 
1174a6d42e7dSPeter Dunlap 	switch (nvp_type) {
1175a6d42e7dSPeter Dunlap 	case DATA_TYPE_NVLIST:
1176a6d42e7dSPeter Dunlap 		nvrc = nvpair_value_nvlist(value_list, &nvl);
1177a6d42e7dSPeter Dunlap 		ASSERT(nvrc == 0);
1178a6d42e7dSPeter Dunlap 		result = nvlist_next_nvpair(nvl, curr_nvp);
1179a6d42e7dSPeter Dunlap 		break;
1180a6d42e7dSPeter Dunlap 	case DATA_TYPE_STRING:
1181a6d42e7dSPeter Dunlap 		/* Single choice */
1182a6d42e7dSPeter Dunlap 		if (curr_nvp == NULL) {
1183a6d42e7dSPeter Dunlap 			result = value_list;
1184a6d42e7dSPeter Dunlap 		} else {
1185a6d42e7dSPeter Dunlap 			result = NULL;
1186a6d42e7dSPeter Dunlap 		}
1187a6d42e7dSPeter Dunlap 		break;
1188a6d42e7dSPeter Dunlap 	default:
1189a6d42e7dSPeter Dunlap 		ASSERT(0); /* Malformed choice list */
1190a6d42e7dSPeter Dunlap 		result = NULL;
1191a6d42e7dSPeter Dunlap 		break;
1192a6d42e7dSPeter Dunlap 	}
1193a6d42e7dSPeter Dunlap 
1194a6d42e7dSPeter Dunlap 	return (result);
1195a6d42e7dSPeter Dunlap }
1196a6d42e7dSPeter Dunlap 
1197a6d42e7dSPeter Dunlap kv_status_t
idm_nvstat_to_kvstat(int nvrc)1198a6d42e7dSPeter Dunlap idm_nvstat_to_kvstat(int nvrc)
1199a6d42e7dSPeter Dunlap {
1200a6d42e7dSPeter Dunlap 	kv_status_t result;
1201a6d42e7dSPeter Dunlap 	switch (nvrc) {
1202a6d42e7dSPeter Dunlap 	case 0:
1203a6d42e7dSPeter Dunlap 		result = KV_HANDLED;
1204a6d42e7dSPeter Dunlap 		break;
1205a6d42e7dSPeter Dunlap 	case ENOMEM:
1206a6d42e7dSPeter Dunlap 		result = KV_NO_RESOURCES;
1207a6d42e7dSPeter Dunlap 		break;
1208a6d42e7dSPeter Dunlap 	case EINVAL:
1209a6d42e7dSPeter Dunlap 		result = KV_VALUE_ERROR;
1210a6d42e7dSPeter Dunlap 		break;
1211a6d42e7dSPeter Dunlap 	case EFAULT:
1212a6d42e7dSPeter Dunlap 	case ENOTSUP:
1213a6d42e7dSPeter Dunlap 	default:
1214a6d42e7dSPeter Dunlap 		result = KV_INTERNAL_ERROR;
1215a6d42e7dSPeter Dunlap 		break;
1216a6d42e7dSPeter Dunlap 	}
1217a6d42e7dSPeter Dunlap 
1218a6d42e7dSPeter Dunlap 	return (result);
1219a6d42e7dSPeter Dunlap }
1220a6d42e7dSPeter Dunlap 
1221a6d42e7dSPeter Dunlap void
idm_kvstat_to_error(kv_status_t kvrc,uint8_t * class,uint8_t * detail)1222a6d42e7dSPeter Dunlap idm_kvstat_to_error(kv_status_t kvrc, uint8_t *class, uint8_t *detail)
1223a6d42e7dSPeter Dunlap {
1224a6d42e7dSPeter Dunlap 	switch (kvrc) {
1225a6d42e7dSPeter Dunlap 	case KV_HANDLED:
1226a6d42e7dSPeter Dunlap 	case KV_HANDLED_NO_TRANSIT:
1227a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_SUCCESS;
1228a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_ACCEPT;
1229a6d42e7dSPeter Dunlap 		break;
1230a6d42e7dSPeter Dunlap 	case KV_UNHANDLED:
1231a6d42e7dSPeter Dunlap 	case KV_TARGET_ONLY:
1232a6d42e7dSPeter Dunlap 		/* protocol error */
1233a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_INITIATOR_ERR;
1234a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_INVALID_REQUEST;
1235a6d42e7dSPeter Dunlap 		break;
1236a6d42e7dSPeter Dunlap 	case KV_VALUE_ERROR:
1237a6d42e7dSPeter Dunlap 		/* invalid value */
1238a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_INITIATOR_ERR;
1239a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_INIT_ERR;
1240a6d42e7dSPeter Dunlap 		break;
1241a6d42e7dSPeter Dunlap 	case KV_NO_RESOURCES:
1242a6d42e7dSPeter Dunlap 		/* no memory */
1243a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_TARGET_ERR;
1244a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1245a6d42e7dSPeter Dunlap 		break;
1246a6d42e7dSPeter Dunlap 	case KV_MISSING_FIELDS:
1247a6d42e7dSPeter Dunlap 		/* key/value pair(s) missing */
1248a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_INITIATOR_ERR;
1249a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS;
1250a6d42e7dSPeter Dunlap 		break;
1251a6d42e7dSPeter Dunlap 	case KV_AUTH_FAILED:
1252a6d42e7dSPeter Dunlap 		/* authentication failed */
1253a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_INITIATOR_ERR;
1254a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_AUTH_FAILED;
1255a6d42e7dSPeter Dunlap 		break;
1256a6d42e7dSPeter Dunlap 	default:
1257a6d42e7dSPeter Dunlap 		/* target error */
1258a6d42e7dSPeter Dunlap 		*class = ISCSI_STATUS_CLASS_TARGET_ERR;
1259a6d42e7dSPeter Dunlap 		*detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
1260a6d42e7dSPeter Dunlap 		break;
1261a6d42e7dSPeter Dunlap 	}
1262a6d42e7dSPeter Dunlap }
1263a6d42e7dSPeter Dunlap 
1264a6d42e7dSPeter Dunlap int
idm_nvlist_add_keyvalue(nvlist_t * nvl,char * key,int keylen,char * value)1265a6d42e7dSPeter Dunlap idm_nvlist_add_keyvalue(nvlist_t *nvl,
1266a6d42e7dSPeter Dunlap     char *key, int keylen, char *value)
1267a6d42e7dSPeter Dunlap {
1268a6d42e7dSPeter Dunlap 	const idm_kv_xlate_t *ikvx;
1269a6d42e7dSPeter Dunlap 
1270a6d42e7dSPeter Dunlap 	ikvx = idm_lookup_kv_xlate(key, keylen);
1271a6d42e7dSPeter Dunlap 
1272a6d42e7dSPeter Dunlap 	if (ikvx->ik_key_id == KI_MAX_KEY) {
1273bc63bc88SJames Moore 		char *nkey;
1274bc63bc88SJames Moore 		int rc;
1275bc63bc88SJames Moore 		size_t len;
1276bc63bc88SJames Moore 
1277bc63bc88SJames Moore 		/*
1278bc63bc88SJames Moore 		 * key is not a NULL terminated string, so create one
1279bc63bc88SJames Moore 		 */
1280bc63bc88SJames Moore 		len = (size_t)(keylen+1);
1281bc63bc88SJames Moore 		nkey = kmem_zalloc(len, KM_SLEEP);
1282bc63bc88SJames Moore 		(void) strncpy(nkey, key, len-1);
1283bc63bc88SJames Moore 		rc = nvlist_add_string(nvl, nkey, value);
1284bc63bc88SJames Moore 		kmem_free(nkey, len);
1285bc63bc88SJames Moore 		return (rc);
1286a6d42e7dSPeter Dunlap 	}
1287a6d42e7dSPeter Dunlap 
1288a6d42e7dSPeter Dunlap 	return (idm_nvlist_add_kv(nvl, ikvx, value));
1289a6d42e7dSPeter Dunlap }
1290a6d42e7dSPeter Dunlap 
1291a6d42e7dSPeter Dunlap int
idm_nvlist_add_id(nvlist_t * nvl,iscsikey_id_t kv_id,char * value)1292a6d42e7dSPeter Dunlap idm_nvlist_add_id(nvlist_t *nvl, iscsikey_id_t kv_id, char *value)
1293a6d42e7dSPeter Dunlap {
1294a6d42e7dSPeter Dunlap 	int i;
1295a6d42e7dSPeter Dunlap 	for (i = 0; i < KI_MAX_KEY; i++) {
1296a6d42e7dSPeter Dunlap 		if (idm_kvpair_xlate[i].ik_key_id == kv_id) {
1297a6d42e7dSPeter Dunlap 			return
1298a6d42e7dSPeter Dunlap 			    (idm_nvlist_add_kv(nvl,
1299a6d42e7dSPeter Dunlap 			    &idm_kvpair_xlate[i], value));
1300a6d42e7dSPeter Dunlap 		}
1301a6d42e7dSPeter Dunlap 	}
1302a6d42e7dSPeter Dunlap 	return (EFAULT);
1303a6d42e7dSPeter Dunlap }
1304a6d42e7dSPeter Dunlap 
1305a6d42e7dSPeter Dunlap char *
idm_id_to_name(iscsikey_id_t kv_id)1306a6d42e7dSPeter Dunlap idm_id_to_name(iscsikey_id_t kv_id)
1307a6d42e7dSPeter Dunlap {
1308a6d42e7dSPeter Dunlap 	int i;
1309a6d42e7dSPeter Dunlap 	for (i = 0; i < KI_MAX_KEY; i++) {
1310a6d42e7dSPeter Dunlap 		if (idm_kvpair_xlate[i].ik_key_id == kv_id) {
1311a6d42e7dSPeter Dunlap 			return (idm_kvpair_xlate[i].ik_key_name);
1312a6d42e7dSPeter Dunlap 		}
1313a6d42e7dSPeter Dunlap 	}
1314a6d42e7dSPeter Dunlap 	return (NULL);
1315a6d42e7dSPeter Dunlap }
1316a6d42e7dSPeter Dunlap 
1317a6d42e7dSPeter Dunlap /*
1318a6d42e7dSPeter Dunlap  * return the value in a buffer that must be freed by the caller
1319a6d42e7dSPeter Dunlap  */
1320a6d42e7dSPeter Dunlap char *
idm_nvpair_value_to_textbuf(nvpair_t * nvp)1321a6d42e7dSPeter Dunlap idm_nvpair_value_to_textbuf(nvpair_t *nvp)
1322a6d42e7dSPeter Dunlap {
1323a6d42e7dSPeter Dunlap 	int rv, len;
1324a6d42e7dSPeter Dunlap 	idm_textbuf_t itb;
1325a6d42e7dSPeter Dunlap 	char *str;
1326a6d42e7dSPeter Dunlap 
1327a6d42e7dSPeter Dunlap 	bzero(&itb, sizeof (itb));
1328a6d42e7dSPeter Dunlap 	rv = idm_itextbuf_add_nvpair(nvp, &itb);
1329a6d42e7dSPeter Dunlap 	if (rv != 0)
1330a6d42e7dSPeter Dunlap 		return (NULL);
1331a6d42e7dSPeter Dunlap 	str = kmem_alloc(itb.itb_mem_len, KM_SLEEP);
1332a6d42e7dSPeter Dunlap 	len = idm_strcspn(itb.itb_mem, "=");
1333a6d42e7dSPeter Dunlap 	if (len > strlen(itb.itb_mem)) {
1334a6d42e7dSPeter Dunlap 		kmem_free(itb.itb_mem, itb.itb_mem_len);
1335a6d42e7dSPeter Dunlap 		return (NULL);
1336a6d42e7dSPeter Dunlap 	}
1337a6d42e7dSPeter Dunlap 	(void) strcpy(str, &itb.itb_mem[len+1]);
1338a6d42e7dSPeter Dunlap 	/* free the allocation done in idm_textbuf_add_nvpair */
1339a6d42e7dSPeter Dunlap 	kmem_free(itb.itb_mem, itb.itb_mem_len);
1340a6d42e7dSPeter Dunlap 	return (str);
1341a6d42e7dSPeter Dunlap }
1342a6d42e7dSPeter Dunlap 
1343a6d42e7dSPeter Dunlap /*
1344a6d42e7dSPeter Dunlap  * build an iscsi text buffer - the memory gets freed in
1345a6d42e7dSPeter Dunlap  * idm_itextbuf_free
1346a6d42e7dSPeter Dunlap  */
1347a6d42e7dSPeter Dunlap void *
idm_nvlist_to_itextbuf(nvlist_t * nvl)1348a6d42e7dSPeter Dunlap idm_nvlist_to_itextbuf(nvlist_t *nvl)
1349a6d42e7dSPeter Dunlap {
1350a6d42e7dSPeter Dunlap 	idm_textbuf_t *itb;
1351a6d42e7dSPeter Dunlap 	char		*textbuf;
1352a6d42e7dSPeter Dunlap 	int		validlen, textbuflen;
1353a6d42e7dSPeter Dunlap 
1354a6d42e7dSPeter Dunlap 	if (idm_nvlist_to_textbuf(nvl, &textbuf, &textbuflen,
1355a6d42e7dSPeter Dunlap 	    &validlen) != IDM_STATUS_SUCCESS) {
1356a6d42e7dSPeter Dunlap 		return (NULL);
1357a6d42e7dSPeter Dunlap 	}
1358a6d42e7dSPeter Dunlap 	itb = kmem_zalloc(sizeof (idm_textbuf_t), KM_SLEEP);
1359a6d42e7dSPeter Dunlap 	ASSERT(itb != NULL);
1360a6d42e7dSPeter Dunlap 	itb->itb_mem = textbuf;
1361a6d42e7dSPeter Dunlap 	itb->itb_mem_len = textbuflen;
1362a6d42e7dSPeter Dunlap 	itb->itb_offset = validlen;
1363a6d42e7dSPeter Dunlap 	return ((void *)itb);
1364a6d42e7dSPeter Dunlap }
1365a6d42e7dSPeter Dunlap 
1366a6d42e7dSPeter Dunlap /*
13674142b486SJames Moore  * Copy as much of the text buffer as will fit in the pdu.
1368a6d42e7dSPeter Dunlap  * The first call to this routine should send
1369a6d42e7dSPeter Dunlap  * a NULL bufptr. Subsequent calls send in the buffer returned.
1370a6d42e7dSPeter Dunlap  * Call this routine until the string returned is NULL
1371a6d42e7dSPeter Dunlap  */
1372a6d42e7dSPeter Dunlap char *
idm_pdu_init_text_data(idm_pdu_t * pdu,void * arg,int max_xfer_len,char * bufptr,int * transit)1373a6d42e7dSPeter Dunlap idm_pdu_init_text_data(idm_pdu_t *pdu, void *arg,
1374a6d42e7dSPeter Dunlap     int max_xfer_len, char *bufptr, int *transit)
1375a6d42e7dSPeter Dunlap {
1376a6d42e7dSPeter Dunlap 	char		*start_ptr, *end_ptr, *ptr;
1377a6d42e7dSPeter Dunlap 	idm_textbuf_t	*itb = arg;
1378a6d42e7dSPeter Dunlap 	iscsi_hdr_t	*ihp = pdu->isp_hdr;
1379a6d42e7dSPeter Dunlap 	int		send = 0;
1380a6d42e7dSPeter Dunlap 
1381a6d42e7dSPeter Dunlap 	ASSERT(itb != NULL);
1382a6d42e7dSPeter Dunlap 	ASSERT(pdu != NULL);
1383a6d42e7dSPeter Dunlap 	ASSERT(transit != NULL);
1384a6d42e7dSPeter Dunlap 	if (bufptr == NULL) {
1385a6d42e7dSPeter Dunlap 		/* first call - check the length */
1386a6d42e7dSPeter Dunlap 		if (itb->itb_offset <= max_xfer_len) {
13874142b486SJames Moore 			/*
13884142b486SJames Moore 			 * the entire text buffer fits in the pdu
13894142b486SJames Moore 			 */
13904142b486SJames Moore 			bcopy((uint8_t *)itb->itb_mem, pdu->isp_data,
13914142b486SJames Moore 			    (size_t)itb->itb_offset);
13924142b486SJames Moore 			pdu->isp_datalen = itb->itb_offset;
1393a6d42e7dSPeter Dunlap 			ihp->flags &= ~ISCSI_FLAG_TEXT_CONTINUE;
1394a6d42e7dSPeter Dunlap 			*transit = 1;
1395a6d42e7dSPeter Dunlap 			return (NULL);
1396a6d42e7dSPeter Dunlap 		}
1397a6d42e7dSPeter Dunlap 		/* we have more data than will fit in one pdu */
1398a6d42e7dSPeter Dunlap 		start_ptr = itb->itb_mem;
1399a6d42e7dSPeter Dunlap 		end_ptr = &itb->itb_mem[max_xfer_len - 1];
1400a6d42e7dSPeter Dunlap 
1401a6d42e7dSPeter Dunlap 	} else {
14024142b486SJames Moore 		uint_t len;
14034142b486SJames Moore 
14044142b486SJames Moore 		len =  (uintptr_t)&itb->itb_mem[itb->itb_offset] -
14054142b486SJames Moore 		    (uintptr_t)bufptr;
14064142b486SJames Moore 		if (len <= max_xfer_len) {
14074142b486SJames Moore 			/*
14084142b486SJames Moore 			 * the remaining text fits in the pdu
14094142b486SJames Moore 			 */
14104142b486SJames Moore 			bcopy(bufptr, pdu->isp_data, (size_t)len);
14114142b486SJames Moore 			pdu->isp_datalen = len;
1412a6d42e7dSPeter Dunlap 			ihp->flags &= ~ISCSI_FLAG_TEXT_CONTINUE;
1413a6d42e7dSPeter Dunlap 			*transit = 1;
1414a6d42e7dSPeter Dunlap 			return (NULL);
1415a6d42e7dSPeter Dunlap 		}
14164142b486SJames Moore 		/* we still have more data then will fit in one pdu */
1417a6d42e7dSPeter Dunlap 		start_ptr = bufptr;
1418a6d42e7dSPeter Dunlap 		end_ptr = &bufptr[max_xfer_len - 1];
1419a6d42e7dSPeter Dunlap 	}
1420a6d42e7dSPeter Dunlap 	/* break after key, after =, after the value or after '\0' */
1421a6d42e7dSPeter Dunlap 	ptr = end_ptr;
1422a6d42e7dSPeter Dunlap 	if (end_ptr + 1 <= &itb->itb_mem[itb->itb_offset]) {
1423a6d42e7dSPeter Dunlap 		/* if next char is an '=' or '\0' send it */
1424a6d42e7dSPeter Dunlap 		if (*(end_ptr + 1) == '=' || *(end_ptr + 1) == '\0') {
1425a6d42e7dSPeter Dunlap 			send = 1;
1426a6d42e7dSPeter Dunlap 		}
1427a6d42e7dSPeter Dunlap 	}
1428a6d42e7dSPeter Dunlap 	if (!send) {
1429a6d42e7dSPeter Dunlap 		while (*ptr != '\0' && *ptr != '=' && ptr != start_ptr) {
1430a6d42e7dSPeter Dunlap 			ptr--;
1431a6d42e7dSPeter Dunlap 		}
1432a6d42e7dSPeter Dunlap 	}
14334142b486SJames Moore 	bcopy(start_ptr, pdu->isp_data,
1434a6d42e7dSPeter Dunlap 	    ((uintptr_t)ptr - (uintptr_t)start_ptr) + 1);
14354142b486SJames Moore 	pdu->isp_datalen = ((uintptr_t)ptr - (uintptr_t)start_ptr) + 1;
1436a6d42e7dSPeter Dunlap 	ihp->flags |= ISCSI_FLAG_TEXT_CONTINUE;
1437a6d42e7dSPeter Dunlap 	*transit = 0;
1438a6d42e7dSPeter Dunlap 	return (++ptr);
1439a6d42e7dSPeter Dunlap }
1440a6d42e7dSPeter Dunlap 
1441a6d42e7dSPeter Dunlap void
idm_itextbuf_free(void * arg)1442a6d42e7dSPeter Dunlap idm_itextbuf_free(void *arg)
1443a6d42e7dSPeter Dunlap {
1444a6d42e7dSPeter Dunlap 	idm_textbuf_t	*itb = arg;
1445a6d42e7dSPeter Dunlap 	ASSERT(itb != NULL);
1446a6d42e7dSPeter Dunlap 	kmem_free(itb->itb_mem, itb->itb_mem_len);
1447a6d42e7dSPeter Dunlap 	kmem_free(itb, sizeof (idm_textbuf_t));
1448a6d42e7dSPeter Dunlap }
1449a6d42e7dSPeter Dunlap 
1450a6d42e7dSPeter Dunlap /*
1451a6d42e7dSPeter Dunlap  * Allocate an nvlist and poputlate with key=value from the pdu list.
1452a6d42e7dSPeter Dunlap  * NOTE: caller must free the list
1453a6d42e7dSPeter Dunlap  */
1454a6d42e7dSPeter Dunlap idm_status_t
idm_pdu_list_to_nvlist(list_t * pdu_list,nvlist_t ** nvlist,uint8_t * error_detail)1455a6d42e7dSPeter Dunlap idm_pdu_list_to_nvlist(list_t *pdu_list, nvlist_t **nvlist,
1456a6d42e7dSPeter Dunlap     uint8_t *error_detail)
1457a6d42e7dSPeter Dunlap {
1458a6d42e7dSPeter Dunlap 	idm_pdu_t		*pdu, *next_pdu;
1459a6d42e7dSPeter Dunlap 	boolean_t		split_kv = B_FALSE;
1460a6d42e7dSPeter Dunlap 	char			*textbuf, *leftover_textbuf = NULL;
1461a6d42e7dSPeter Dunlap 	int			textbuflen, leftover_textbuflen = 0;
1462a6d42e7dSPeter Dunlap 	char			*split_kvbuf;
1463a6d42e7dSPeter Dunlap 	int			split_kvbuflen, cont_fraglen;
1464a6d42e7dSPeter Dunlap 	iscsi_login_hdr_t	*lh;
1465a6d42e7dSPeter Dunlap 	int			rc;
1466a6d42e7dSPeter Dunlap 	int			ret = IDM_STATUS_SUCCESS;
1467a6d42e7dSPeter Dunlap 
1468a6d42e7dSPeter Dunlap 	*error_detail = ISCSI_LOGIN_STATUS_ACCEPT;
1469a6d42e7dSPeter Dunlap 	/* Allocate a new nvlist for request key/value pairs */
1470a6d42e7dSPeter Dunlap 	rc = nvlist_alloc(nvlist, NV_UNIQUE_NAME,
1471a6d42e7dSPeter Dunlap 	    KM_NOSLEEP);
1472a6d42e7dSPeter Dunlap 	if (rc != 0) {
1473a6d42e7dSPeter Dunlap 		*error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1474a6d42e7dSPeter Dunlap 		ret = IDM_STATUS_FAIL;
1475a6d42e7dSPeter Dunlap 		goto cleanup;
1476a6d42e7dSPeter Dunlap 	}
1477a6d42e7dSPeter Dunlap 
1478a6d42e7dSPeter Dunlap 	/*
1479a6d42e7dSPeter Dunlap 	 * A login request can be split across multiple PDU's.  The state
1480a6d42e7dSPeter Dunlap 	 * machine has collected all the PDU's that make up this login request
1481a6d42e7dSPeter Dunlap 	 * and assembled them on the "icl_pdu_list" queue.  Process each PDU
1482a6d42e7dSPeter Dunlap 	 * and convert the text keywords to nvlist form.
1483a6d42e7dSPeter Dunlap 	 */
1484a6d42e7dSPeter Dunlap 	pdu = list_head(pdu_list);
1485a6d42e7dSPeter Dunlap 	while (pdu != NULL) {
1486a6d42e7dSPeter Dunlap 		next_pdu = list_next(pdu_list, pdu);
1487a6d42e7dSPeter Dunlap 
1488a6d42e7dSPeter Dunlap 		lh = (iscsi_login_hdr_t *)pdu->isp_hdr;
1489a6d42e7dSPeter Dunlap 
1490a6d42e7dSPeter Dunlap 		textbuf = (char *)pdu->isp_data;
1491a6d42e7dSPeter Dunlap 		textbuflen = pdu->isp_datalen;
1492a6d42e7dSPeter Dunlap 		if (textbuflen == 0) {
1493a6d42e7dSPeter Dunlap 			/* This shouldn't really happen but it could.. */
1494a6d42e7dSPeter Dunlap 			list_remove(pdu_list, pdu);
1495a6d42e7dSPeter Dunlap 			idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1496a6d42e7dSPeter Dunlap 			pdu = next_pdu;
1497a6d42e7dSPeter Dunlap 			continue;
1498a6d42e7dSPeter Dunlap 		}
1499a6d42e7dSPeter Dunlap 
1500a6d42e7dSPeter Dunlap 		/*
1501a6d42e7dSPeter Dunlap 		 * If we encountered a split key-value pair on the last
1502a6d42e7dSPeter Dunlap 		 * PDU then handle it now by grabbing the remainder of the
1503a6d42e7dSPeter Dunlap 		 * key-value pair from the next PDU and splicing them
1504a6d42e7dSPeter Dunlap 		 * together.  Obviously on the first PDU this will never
1505a6d42e7dSPeter Dunlap 		 * happen.
1506a6d42e7dSPeter Dunlap 		 */
1507a6d42e7dSPeter Dunlap 		if (split_kv) {
1508a6d42e7dSPeter Dunlap 			cont_fraglen = idm_textbuf_to_firstfraglen(textbuf,
1509a6d42e7dSPeter Dunlap 			    textbuflen);
1510a6d42e7dSPeter Dunlap 			if (cont_fraglen == pdu->isp_datalen) {
1511a6d42e7dSPeter Dunlap 				/*
1512a6d42e7dSPeter Dunlap 				 * This key-value pair spans more than two
1513a6d42e7dSPeter Dunlap 				 * PDU's.  We don't handle this.
1514a6d42e7dSPeter Dunlap 				 */
1515a6d42e7dSPeter Dunlap 				*error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
1516a6d42e7dSPeter Dunlap 				ret = IDM_STATUS_FAIL;
1517a6d42e7dSPeter Dunlap 				goto cleanup;
1518a6d42e7dSPeter Dunlap 			}
1519a6d42e7dSPeter Dunlap 
1520a6d42e7dSPeter Dunlap 			split_kvbuflen = leftover_textbuflen + cont_fraglen;
1521a6d42e7dSPeter Dunlap 			split_kvbuf = kmem_alloc(split_kvbuflen, KM_NOSLEEP);
1522a6d42e7dSPeter Dunlap 			if (split_kvbuf == NULL) {
1523a6d42e7dSPeter Dunlap 				*error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES;
1524a6d42e7dSPeter Dunlap 				ret = IDM_STATUS_FAIL;
1525a6d42e7dSPeter Dunlap 				goto cleanup;
1526a6d42e7dSPeter Dunlap 			}
1527a6d42e7dSPeter Dunlap 
1528a6d42e7dSPeter Dunlap 			bcopy(leftover_textbuf, split_kvbuf,
1529a6d42e7dSPeter Dunlap 			    leftover_textbuflen);
1530a6d42e7dSPeter Dunlap 			bcopy(textbuf,
1531a6d42e7dSPeter Dunlap 			    (uint8_t *)split_kvbuf + leftover_textbuflen,
1532a6d42e7dSPeter Dunlap 			    cont_fraglen);
1533a6d42e7dSPeter Dunlap 
1534a6d42e7dSPeter Dunlap 
1535a6d42e7dSPeter Dunlap 			if (idm_textbuf_to_nvlist(*nvlist,
1536a6d42e7dSPeter Dunlap 			    &split_kvbuf, &split_kvbuflen) != 0) {
1537a6d42e7dSPeter Dunlap 				/*
1538a6d42e7dSPeter Dunlap 				 * Need to handle E2BIG case, indicating that
1539a6d42e7dSPeter Dunlap 				 * a key-value pair is split across multiple
1540a6d42e7dSPeter Dunlap 				 * PDU's.
1541a6d42e7dSPeter Dunlap 				 */
1542a6d42e7dSPeter Dunlap 				kmem_free(split_kvbuf, split_kvbuflen);
1543a6d42e7dSPeter Dunlap 
1544a6d42e7dSPeter Dunlap 				*error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
1545a6d42e7dSPeter Dunlap 				ret = IDM_STATUS_FAIL;
1546a6d42e7dSPeter Dunlap 				goto cleanup;
1547a6d42e7dSPeter Dunlap 			}
1548a6d42e7dSPeter Dunlap 
1549*2fcabb59SToomas Soome 			ASSERT(split_kvbuflen != 0);
1550a6d42e7dSPeter Dunlap 			kmem_free(split_kvbuf, split_kvbuflen);
1551a6d42e7dSPeter Dunlap 
1552a6d42e7dSPeter Dunlap 			/* Now handle the remainder of the PDU as normal */
1553a6d42e7dSPeter Dunlap 			textbuf += (cont_fraglen + 1);
1554a6d42e7dSPeter Dunlap 			textbuflen -= (cont_fraglen + 1);
1555a6d42e7dSPeter Dunlap 		}
1556a6d42e7dSPeter Dunlap 
1557a6d42e7dSPeter Dunlap 		/*
1558a6d42e7dSPeter Dunlap 		 * Convert each key-value pair in the text buffer to nvlist
1559a6d42e7dSPeter Dunlap 		 * format.  If the list has already been created the nvpair
1560a6d42e7dSPeter Dunlap 		 * elements will be added on to the existing list.  Otherwise
1561a6d42e7dSPeter Dunlap 		 * a new nvlist will be created.
1562a6d42e7dSPeter Dunlap 		 */
1563a6d42e7dSPeter Dunlap 		if (idm_textbuf_to_nvlist(*nvlist,
1564a6d42e7dSPeter Dunlap 		    &textbuf, &textbuflen) != 0) {
1565a6d42e7dSPeter Dunlap 
1566a6d42e7dSPeter Dunlap 			*error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR;
1567a6d42e7dSPeter Dunlap 			ret = IDM_STATUS_FAIL;
1568a6d42e7dSPeter Dunlap 			goto cleanup;
1569a6d42e7dSPeter Dunlap 		}
1570a6d42e7dSPeter Dunlap 
1571a6d42e7dSPeter Dunlap 		ASSERT(
1572a6d42e7dSPeter Dunlap 		    ((lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) &&
1573a6d42e7dSPeter Dunlap 		    (next_pdu != NULL)) ||
1574a6d42e7dSPeter Dunlap 		    (!(lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) &&
1575a6d42e7dSPeter Dunlap 		    (next_pdu == NULL)));
1576a6d42e7dSPeter Dunlap 
1577a6d42e7dSPeter Dunlap 		if ((lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) &
1578a6d42e7dSPeter Dunlap 		    (textbuflen != 0)) {
1579a6d42e7dSPeter Dunlap 			/*
1580a6d42e7dSPeter Dunlap 			 * Key-value pair is split over two PDU's.  We
1581a6d42e7dSPeter Dunlap 			 * assume it willl never be split over more than
1582a6d42e7dSPeter Dunlap 			 * two PDU's.
1583a6d42e7dSPeter Dunlap 			 */
1584a6d42e7dSPeter Dunlap 			split_kv = B_TRUE;
1585a6d42e7dSPeter Dunlap 			leftover_textbuf = textbuf;
1586a6d42e7dSPeter Dunlap 			leftover_textbuflen = textbuflen;
1587a6d42e7dSPeter Dunlap 		} else {
1588a6d42e7dSPeter Dunlap 			split_kv = B_FALSE;
1589a6d42e7dSPeter Dunlap 			if (textbuflen != 0) {
1590a6d42e7dSPeter Dunlap 				/*
1591a6d42e7dSPeter Dunlap 				 * Incomplete keyword but no additional
1592a6d42e7dSPeter Dunlap 				 * PDU's.  This is a malformed login
1593a6d42e7dSPeter Dunlap 				 * request.
1594a6d42e7dSPeter Dunlap 				 */
1595a6d42e7dSPeter Dunlap 				*error_detail =
1596a6d42e7dSPeter Dunlap 				    ISCSI_LOGIN_STATUS_INVALID_REQUEST;
1597a6d42e7dSPeter Dunlap 				ret = IDM_STATUS_FAIL;
1598a6d42e7dSPeter Dunlap 				goto cleanup;
1599a6d42e7dSPeter Dunlap 			}
1600a6d42e7dSPeter Dunlap 		}
1601a6d42e7dSPeter Dunlap 
1602a6d42e7dSPeter Dunlap 		list_remove(pdu_list, pdu);
1603a6d42e7dSPeter Dunlap 		idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1604a6d42e7dSPeter Dunlap 		pdu = next_pdu;
1605a6d42e7dSPeter Dunlap 	}
1606a6d42e7dSPeter Dunlap 
1607a6d42e7dSPeter Dunlap cleanup:
1608a6d42e7dSPeter Dunlap 
1609a6d42e7dSPeter Dunlap 	/*
1610a6d42e7dSPeter Dunlap 	 * Free any remaining PDUs on the list. This will only
1611a6d42e7dSPeter Dunlap 	 * happen if there were errors encountered during
1612a6d42e7dSPeter Dunlap 	 * processing of the textbuf.
1613a6d42e7dSPeter Dunlap 	 */
1614a6d42e7dSPeter Dunlap 	pdu = list_head(pdu_list);
1615a6d42e7dSPeter Dunlap 	while (pdu != NULL) {
1616a6d42e7dSPeter Dunlap 		next_pdu = list_next(pdu_list, pdu);
1617a6d42e7dSPeter Dunlap 		list_remove(pdu_list, pdu);
1618a6d42e7dSPeter Dunlap 		idm_pdu_complete(pdu, IDM_STATUS_SUCCESS);
1619a6d42e7dSPeter Dunlap 		pdu = next_pdu;
1620a6d42e7dSPeter Dunlap 	}
1621a6d42e7dSPeter Dunlap 
1622a6d42e7dSPeter Dunlap 	/*
1623a6d42e7dSPeter Dunlap 	 * If there were no errors, we have a complete nvlist representing
1624a6d42e7dSPeter Dunlap 	 * all the iSCSI key-value pairs in the login request PDU's
1625a6d42e7dSPeter Dunlap 	 * that make up this request.
1626a6d42e7dSPeter Dunlap 	 */
1627a6d42e7dSPeter Dunlap 	return (ret);
1628a6d42e7dSPeter Dunlap }
1629