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