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 },
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 {