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