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