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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
30 #include <sys/sunddi.h>
31 #include <sys/sysmacros.h>
32 #include <sys/socket.h>
34 #include <sys/iscsi_protocol.h>
35 #include <sys/idm/idm.h>
36 #include <sys/idm/idm_text.h>
40 iscsi_base64_str_to_binary(char *hstr
, int hstr_len
,
41 uint8_t *binary
, int binary_buf_len
, int *out_len
);
44 static const char idm_hex_to_ascii
[] = "0123456789abcdefABCDEF";
46 static const idm_kv_xlate_t idm_kvpair_xlate
[] = {
48 * iSCSI Security Text Keys and Authentication Methods
51 { KI_AUTH_METHOD
, "AuthMethod", KT_LIST_OF_VALUES
, B_FALSE
},
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
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
},
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
},
70 * U, s, A, B, M, and H(A | M | K) are defined in [RFC2945]
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
},
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
},
91 * ISCSI Operational Parameter Keys
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
},
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
},
142 * Table terminator. The type KT_TEXT will allow the response
143 * value of "NotUnderstood".
145 { KI_MAX_KEY
, NULL
, KT_TEXT
, B_TRUE
} /* Terminator */
149 #define TEXTBUF_CHUNKSIZE 8192
158 * Ignore all but the following keys during security negotiation
166 * TargetPortalGroupTag
167 * AuthMethod and associated auth keys
170 static int idm_keyvalue_get_next(char **tb_scan
, int *tb_len
,
171 char **key
, int *keylen
, char **value
);
173 static int idm_nvlist_add_kv(nvlist_t
*nvl
, const idm_kv_xlate_t
*ikvx
,
176 static int idm_nvlist_add_string(nvlist_t
*nvl
,
177 const idm_kv_xlate_t
*ikvx
, char *value
);
179 static int idm_nvlist_add_boolean(nvlist_t
*nvl
,
180 const idm_kv_xlate_t
*ikvx
, char *value
);
182 static int idm_nvlist_add_binary(nvlist_t
*nvl
,
183 const idm_kv_xlate_t
*ikvx
, char *value
);
185 static int idm_nvlist_add_large_numerical(nvlist_t
*nvl
,
186 const idm_kv_xlate_t
*ikvx
, char *value
);
188 static int idm_nvlist_add_numerical(nvlist_t
*nvl
,
189 const idm_kv_xlate_t
*ikvx
, char *value
);
191 static int idm_nvlist_add_numeric_range(nvlist_t
*nvl
,
192 const idm_kv_xlate_t
*ikvx
, char *value
);
194 static int idm_nvlist_add_list_of_values(nvlist_t
*nvl
,
195 const idm_kv_xlate_t
*ikvx
, char *value
);
197 static int idm_itextbuf_add_nvpair(nvpair_t
*nvp
, idm_textbuf_t
*itb
);
199 static int idm_itextbuf_add_string(nvpair_t
*nvp
,
200 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
202 static int idm_itextbuf_add_boolean(nvpair_t
*nvp
,
203 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
205 static int idm_itextbuf_add_binary(nvpair_t
*nvp
,
206 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
208 static int idm_itextbuf_add_large_numerical(nvpair_t
*nvp
,
209 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
211 static int idm_itextbuf_add_numerical(nvpair_t
*nvp
,
212 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
214 static int idm_itextbuf_add_numeric_range(nvpair_t
*nvp
,
215 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
217 static int idm_itextbuf_add_list_of_values(nvpair_t
*nvp
,
218 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
);
220 static void textbuf_memcpy(idm_textbuf_t
*itb
, void *mem
, int mem_len
);
222 static void textbuf_strcpy(idm_textbuf_t
*itb
, char *str
);
224 static void textbuf_append_char(idm_textbuf_t
*itb
, char c
);
226 static void textbuf_terminate_kvpair(idm_textbuf_t
*itb
);
228 static int idm_ascii_to_hex(char *enc_hex_byte
, uint8_t *bin_val
);
230 static int idm_base16_str_to_binary(char *hstr
, int hstr_len
,
231 uint8_t *binary
, int binary_length
);
233 static size_t idm_strcspn(const char *string
, const char *charset
);
235 static size_t idm_strnlen(const char *str
, size_t maxlen
);
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.
247 * textbuflen includes the trailing 0x00!
251 idm_textbuf_to_nvlist(nvlist_t
*nvl
, char **textbuf
, int *textbuflen
)
254 char *tbscan
, *key
, *value
;
261 if ((rc
= idm_keyvalue_get_next(&tbscan
, &tblen
,
262 &key
, &keylen
, &value
)) != 0) {
263 /* There was a problem reading the key/value pair */
267 if ((rc
= idm_nvlist_add_keyvalue(nvl
,
268 key
, keylen
, value
)) != 0) {
269 /* Something was wrong with either the key or value */
274 /* End of text buffer */
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.
294 idm_textbuf_to_firstfraglen(void *textbuf
, int textbuflen
)
296 return (idm_strnlen(textbuf
, textbuflen
));
300 idm_keyvalue_get_next(char **tb_scan
, int *tb_len
,
301 char **key
, int *keylen
, char **value
)
304 * Caller doesn't need "valuelen" returned since "value" will
305 * always be a NULL-terminated string.
307 size_t total_len
, valuelen
;
310 * How many bytes to the first '\0'? This represents the total
311 * length of our iSCSI key/value pair.
313 total_len
= idm_strnlen(*tb_scan
, *tb_len
);
314 if (total_len
== *tb_len
) {
316 * No '\0', perhaps this key/value pair is continued in
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)
329 *keylen
= idm_strcspn(*tb_scan
, "=");
331 if (*keylen
== total_len
) {
332 /* No '=', bad format */
336 *tb_scan
+= *keylen
+ 1; /* Skip the '=' */
337 *tb_len
-= *keylen
+ 1;
340 * The remaining text after the '=' is the value
343 valuelen
= total_len
- (*keylen
+ 1);
345 *tb_scan
+= valuelen
+ 1; /* Skip the '\0' */
346 *tb_len
-= valuelen
+ 1;
351 const idm_kv_xlate_t
*
352 idm_lookup_kv_xlate(const char *key
, int keylen
)
354 const idm_kv_xlate_t
*ikvx
= &idm_kvpair_xlate
[0];
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.
364 while (ikvx
->ik_key_id
!= KI_MAX_KEY
) {
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).
372 * "value" is NULL-terminated so we can use it as
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 */
381 /* No match, look at the next entry */
389 idm_nvlist_add_kv(nvlist_t
*nvl
, const idm_kv_xlate_t
*ikvx
, char *value
)
393 switch (ikvx
->ik_idm_type
) {
397 case KT_ISCSI_LOCAL_NAME
:
398 rc
= idm_nvlist_add_string(nvl
, ikvx
, value
);
401 rc
= idm_nvlist_add_boolean(nvl
, ikvx
, value
);
403 case KT_REGULAR_BINARY
:
404 case KT_LARGE_BINARY
:
406 rc
= idm_nvlist_add_binary(nvl
, ikvx
, value
);
408 case KT_LARGE_NUMERICAL
:
409 rc
= idm_nvlist_add_large_numerical(nvl
, ikvx
,
413 rc
= idm_nvlist_add_numerical(nvl
, ikvx
,
416 case KT_NUMERIC_RANGE
:
417 rc
= idm_nvlist_add_numeric_range(nvl
, ikvx
,
420 case KT_LIST_OF_VALUES
:
421 rc
= idm_nvlist_add_list_of_values(nvl
, ikvx
,
425 ASSERT(0); /* This should never happen */
429 /* could be one of the text constants */
430 rc
= idm_nvlist_add_string(nvl
, ikvx
, value
);
437 idm_nvlist_add_string(nvlist_t
*nvl
,
438 const idm_kv_xlate_t
*ikvx
, char *value
)
440 return (nvlist_add_string(nvl
, ikvx
->ik_key_name
, value
));
444 idm_nvlist_add_boolean(nvlist_t
*nvl
,
445 const idm_kv_xlate_t
*ikvx
, char *value
)
450 if (strcasecmp(value
, "Yes") == 0) {
452 } else if (strcasecmp(value
, "No") == 0) {
458 rc
= nvlist_add_boolean_value(nvl
, ikvx
->ik_key_name
, bool_val
);
464 kv_is_hex(char *value
)
466 return ((strncmp(value
, "0x", strlen("0x")) == 0) ||
467 (strncmp(value
, "0X", strlen("0X")) == 0));
471 kv_is_base64(char *value
)
473 return ((strncmp(value
, "0b", strlen("0b")) == 0) ||
474 (strncmp(value
, "0B", strlen("0B")) == 0));
479 idm_nvlist_add_binary(nvlist_t
*nvl
,
480 const idm_kv_xlate_t
*ikvx
, char *value
)
484 uint64_t uint64_value
;
486 uchar_t
*binary_array
;
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.
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
);
502 if (idm_base16_str_to_binary(value
, value_length
,
503 binary_array
, binary_length
) != 0) {
504 kmem_free(binary_array
, binary_length
);
508 rc
= nvlist_add_byte_array(nvl
, ikvx
->ik_key_name
,
509 binary_array
, binary_length
);
511 kmem_free(binary_array
, binary_length
);
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
) {
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
);
529 rc
= nvlist_add_byte_array(nvl
, ikvx
->ik_key_name
,
530 binary_array
, binary_length
);
532 kmem_free(binary_array
, value_length
);
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.
544 if ((rc
= ddi_strtoull(value
, NULL
, 0,
545 (u_longlong_t
*)&uint64_value
)) != 0)
548 rc
= nvlist_add_byte_array(nvl
, ikvx
->ik_key_name
,
549 (uint8_t *)&uint64_value
, sizeof (uint64_value
));
559 idm_nvlist_add_large_numerical(nvlist_t
*nvl
,
560 const idm_kv_xlate_t
*ikvx
, char *value
)
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.
568 return (nvlist_add_string(nvl
, ikvx
->ik_key_name
, value
));
573 idm_nvlist_add_numerical(nvlist_t
*nvl
,
574 const idm_kv_xlate_t
*ikvx
, char *value
)
577 uint64_t uint64_value
;
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.
585 rc
= ddi_strtoull(value
, NULL
, 0, (u_longlong_t
*)&uint64_value
);
587 rc
= nvlist_add_uint64(nvl
, ikvx
->ik_key_name
, uint64_value
);
595 idm_nvlist_add_numeric_range(nvlist_t
*nvl
,
596 const idm_kv_xlate_t
*ikvx
, char *range
)
599 char *val_scan
= range
;
600 uint64_t start_val
, end_val
;
601 int val_len
, range_len
;
604 /* We'll store the range an an nvlist with two values */
605 rc
= nvlist_alloc(&range_nvl
, NV_UNIQUE_NAME
, KM_NOSLEEP
);
611 * We expect idm_keyvalue_get_next to ensure the string is
614 range_len
= strlen(range
);
617 * Find range separator
619 val_len
= idm_strcspn(val_scan
, "~");
621 if (val_len
== range_len
) {
623 nvlist_free(range_nvl
);
630 *(val_scan
+ val_len
+ 1) = '\0';
631 rc
= ddi_strtoull(val_scan
, NULL
, 0, (u_longlong_t
*)&start_val
);
633 rc
= nvlist_add_uint64(range_nvl
, "start", start_val
);
636 nvlist_free(range_nvl
);
643 val_scan
+= val_len
+ 1;
644 rc
= ddi_strtoull(val_scan
, NULL
, 0, (u_longlong_t
*)&end_val
);
646 rc
= nvlist_add_uint64(range_nvl
, "start", end_val
);
649 nvlist_free(range_nvl
);
654 * Now add the "range" nvlist to the main nvlist
656 rc
= nvlist_add_nvlist(nvl
, ikvx
->ik_key_name
, range_nvl
);
658 nvlist_free(range_nvl
);
662 nvlist_free(range_nvl
);
668 idm_nvlist_add_list_of_values(nvlist_t
*nvl
,
669 const idm_kv_xlate_t
*ikvx
, char *value_list
)
672 nvlist_t
*value_list_nvl
;
673 char *val_scan
= value_list
;
675 int val_len
, val_list_len
;
678 rc
= nvlist_alloc(&value_list_nvl
, NV_UNIQUE_NAME
, KM_NOSLEEP
);
684 * We expect idm_keyvalue_get_next to ensure the string is
687 val_list_len
= strlen(value_list
);
688 if (val_list_len
== 0) {
689 nvlist_free(value_list_nvl
);
694 (void) snprintf(value_name
, 8, "value%d", value_index
);
696 val_len
= idm_strcspn(val_scan
, ",");
698 if (*(val_scan
+ val_len
) != '\0') {
699 *(val_scan
+ val_len
) = '\0';
701 rc
= nvlist_add_string(value_list_nvl
, value_name
, val_scan
);
703 nvlist_free(value_list_nvl
);
708 * Move to next value, see if we're at the end of the value
711 val_scan
+= val_len
+ 1;
712 if (val_scan
== value_list
+ val_list_len
+ 1) {
719 rc
= nvlist_add_nvlist(nvl
, ikvx
->ik_key_name
, value_list_nvl
);
721 nvlist_free(value_list_nvl
);
725 nvlist_free(value_list_nvl
);
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.
737 idm_nvlist_to_textbuf(nvlist_t
*nvl
, char **textbuf
, int *textbuflen
,
741 nvpair_t
*nvp
= NULL
;
744 bzero(&itb
, sizeof (itb
));
747 nvp
= nvlist_next_nvpair(nvl
, nvp
);
750 /* Last nvpair in nvlist, we're done */
754 if ((rc
= idm_itextbuf_add_nvpair(nvp
, &itb
)) != 0) {
755 /* There was a problem building the key/value pair */
760 *textbuf
= itb
.itb_mem
;
761 *textbuflen
= itb
.itb_mem_len
;
762 *validlen
= itb
.itb_offset
;
768 idm_itextbuf_add_nvpair(nvpair_t
*nvp
,
773 const idm_kv_xlate_t
*ikvx
;
775 key
= nvpair_name(nvp
);
777 ikvx
= idm_lookup_kv_xlate(key
, strlen(key
));
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.
784 ASSERT((ikvx
->ik_key_id
!= KI_MAX_KEY
) ||
785 (nvpair_type(nvp
) == DATA_TYPE_STRING
));
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.
792 switch (ikvx
->ik_idm_type
) {
796 case KT_ISCSI_LOCAL_NAME
:
797 rc
= idm_itextbuf_add_string(nvp
, ikvx
, itb
);
800 rc
= idm_itextbuf_add_boolean(nvp
, ikvx
, itb
);
802 case KT_REGULAR_BINARY
:
803 case KT_LARGE_BINARY
:
805 rc
= idm_itextbuf_add_binary(nvp
, ikvx
, itb
);
807 case KT_LARGE_NUMERICAL
:
808 rc
= idm_itextbuf_add_large_numerical(nvp
, ikvx
, itb
);
811 rc
= idm_itextbuf_add_numerical(nvp
, ikvx
, itb
);
813 case KT_NUMERIC_RANGE
:
814 rc
= idm_itextbuf_add_numeric_range(nvp
, ikvx
, itb
);
816 case KT_LIST_OF_VALUES
:
817 rc
= idm_itextbuf_add_list_of_values(nvp
, ikvx
, itb
);
820 ASSERT(0); /* This should never happen */
829 idm_itextbuf_add_string(nvpair_t
*nvp
,
830 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
)
836 /* Start with the key name */
837 key_name
= nvpair_name(nvp
);
838 textbuf_strcpy(itb
, key_name
);
841 textbuf_append_char(itb
, '=');
844 rc
= nvpair_value_string(nvp
, &value
);
846 textbuf_strcpy(itb
, value
);
848 /* Add trailing 0x00 */
849 textbuf_terminate_kvpair(itb
);
857 idm_itextbuf_add_boolean(nvpair_t
*nvp
,
858 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
)
864 /* Start with the key name */
865 key_name
= nvpair_name(nvp
);
866 textbuf_strcpy(itb
, key_name
);
869 textbuf_append_char(itb
, '=');
872 rc
= nvpair_value_boolean_value(nvp
, &value
);
874 textbuf_strcpy(itb
, value
? "Yes" : "No");
876 /* Add trailing 0x00 */
877 textbuf_terminate_kvpair(itb
);
884 idm_itextbuf_add_binary(nvpair_t
*nvp
,
885 const idm_kv_xlate_t
*ikvx
, idm_textbuf_t
*itb
)
888 unsigned char *value
;
893 /* Start with the key name */
894 key_name
= nvpair_name(nvp
);
895 textbuf_strcpy(itb
, key_name
);
898 textbuf_append_char(itb
, '=');
901 rc
= nvpair_value_byte_array(nvp
, &value
, &len
);
904 textbuf_strcpy(itb
, "0x");
910 textbuf_append_char(itb
, idm_hex_to_ascii
[(n
>> 4) & 0xf]);
911 textbuf_append_char(itb
, idm_hex_to_ascii
[n
& 0xf]);
914 /* Add trailing 0x00 */
915 textbuf_terminate_kvpair(itb
);
922 idm_itextbuf_add_large_numerical(nvpair_t
*nvp
,
923 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
)
939 /* Start with the key name */
940 key_name
= nvpair_name(nvp
);
941 textbuf_strcpy(itb
, key_name
);
944 textbuf_append_char(itb
, '=');
947 rc
= nvpair_value_uint64(nvp
, &value
);
949 (void) sprintf(str
, "%llu", (u_longlong_t
)value
);
950 textbuf_strcpy(itb
, str
);
952 /* Add trailing 0x00 */
953 textbuf_terminate_kvpair(itb
);
960 idm_itextbuf_add_numeric_range(nvpair_t
*nvp
,
961 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
)
973 nvpair_t
*vchoice
= NULL
;
974 char *vchoice_string
= NULL
;
977 /* Start with the key name */
978 key_name
= nvpair_name(nvp
);
979 textbuf_strcpy(itb
, key_name
);
982 textbuf_append_char(itb
, '=');
984 /* Add value choices */
985 vchoice
= idm_get_next_listvalue(nvp
, NULL
);
986 while (vchoice
!= NULL
) {
987 rc
= nvpair_value_string(vchoice
, &vchoice_string
);
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
, ',');
997 /* Add trailing 0x00 */
998 textbuf_terminate_kvpair(itb
);
1005 textbuf_makeroom(idm_textbuf_t
*itb
, int size
)
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
;
1024 textbuf_memcpy(idm_textbuf_t
*itb
, void *mem
, int mem_len
)
1026 textbuf_makeroom(itb
, mem_len
);
1027 (void) memcpy(itb
->itb_mem
+ itb
->itb_offset
, mem
, mem_len
);
1028 itb
->itb_offset
+= mem_len
;
1032 textbuf_strcpy(idm_textbuf_t
*itb
, char *str
)
1034 textbuf_memcpy(itb
, str
, strlen(str
));
1038 textbuf_append_char(idm_textbuf_t
*itb
, char c
)
1040 textbuf_makeroom(itb
, sizeof (char));
1041 *(itb
->itb_mem
+ itb
->itb_offset
) = c
;
1046 textbuf_terminate_kvpair(idm_textbuf_t
*itb
)
1048 textbuf_append_char(itb
, '\0');
1052 idm_ascii_to_hex(char *enc_hex_byte
, uint8_t *bin_val
)
1054 uint8_t nibble1
, nibble2
;
1055 char enc_char
= *enc_hex_byte
;
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'));
1068 enc_char
= *enc_hex_byte
;
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'));
1080 *bin_val
= (nibble1
<< 4) | nibble2
;
1086 static int idm_base16_str_to_binary(char *hstr
, int hstr_len
,
1087 uint8_t *binary_array
, int binary_length
)
1090 uchar_t
*binary_scan
;
1092 binary_scan
= binary_array
;
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
1102 if ((hstr_len
% 2) != 0) {
1107 if (idm_ascii_to_hex(tmpstr
, binary_scan
) != 0) {
1115 while (binary_scan
!= binary_array
+ binary_length
) {
1116 if (idm_ascii_to_hex(hstr
, binary_scan
) != 0) {
1128 idm_strnlen(const char *str
, size_t maxlen
)
1132 ptr
= memchr(str
, 0, maxlen
);
1136 return ((uintptr_t)ptr
- (uintptr_t)str
);
1141 idm_strcspn(const char *string
, const char *charset
)
1145 for (q
= string
; *q
!= '\0'; ++q
) {
1146 for (p
= charset
; *p
!= '\0' && *p
!= *q
; )
1152 return ((uintptr_t)q
- (uintptr_t)string
);
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.
1162 * nvpair_t's that contain choices are always strings.
1165 idm_get_next_listvalue(nvpair_t
*value_list
, nvpair_t
*curr_nvp
)
1170 data_type_t nvp_type
;
1172 nvp_type
= nvpair_type(value_list
);
1175 case DATA_TYPE_NVLIST
:
1176 nvrc
= nvpair_value_nvlist(value_list
, &nvl
);
1178 result
= nvlist_next_nvpair(nvl
, curr_nvp
);
1180 case DATA_TYPE_STRING
:
1182 if (curr_nvp
== NULL
) {
1183 result
= value_list
;
1189 ASSERT(0); /* Malformed choice list */
1198 idm_nvstat_to_kvstat(int nvrc
)
1203 result
= KV_HANDLED
;
1206 result
= KV_NO_RESOURCES
;
1209 result
= KV_VALUE_ERROR
;
1214 result
= KV_INTERNAL_ERROR
;
1222 idm_kvstat_to_error(kv_status_t kvrc
, uint8_t *class, uint8_t *detail
)
1226 case KV_HANDLED_NO_TRANSIT
:
1227 *class = ISCSI_STATUS_CLASS_SUCCESS
;
1228 *detail
= ISCSI_LOGIN_STATUS_ACCEPT
;
1231 case KV_TARGET_ONLY
:
1232 /* protocol error */
1233 *class = ISCSI_STATUS_CLASS_INITIATOR_ERR
;
1234 *detail
= ISCSI_LOGIN_STATUS_INVALID_REQUEST
;
1236 case KV_VALUE_ERROR
:
1238 *class = ISCSI_STATUS_CLASS_INITIATOR_ERR
;
1239 *detail
= ISCSI_LOGIN_STATUS_INIT_ERR
;
1241 case KV_NO_RESOURCES
:
1243 *class = ISCSI_STATUS_CLASS_TARGET_ERR
;
1244 *detail
= ISCSI_LOGIN_STATUS_NO_RESOURCES
;
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
;
1251 case KV_AUTH_FAILED
:
1252 /* authentication failed */
1253 *class = ISCSI_STATUS_CLASS_INITIATOR_ERR
;
1254 *detail
= ISCSI_LOGIN_STATUS_AUTH_FAILED
;
1258 *class = ISCSI_STATUS_CLASS_TARGET_ERR
;
1259 *detail
= ISCSI_LOGIN_STATUS_TARGET_ERROR
;
1265 idm_nvlist_add_keyvalue(nvlist_t
*nvl
,
1266 char *key
, int keylen
, char *value
)
1268 const idm_kv_xlate_t
*ikvx
;
1270 ikvx
= idm_lookup_kv_xlate(key
, keylen
);
1272 if (ikvx
->ik_key_id
== KI_MAX_KEY
) {
1278 * key is not a NULL terminated string, so create one
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
);
1288 return (idm_nvlist_add_kv(nvl
, ikvx
, value
));
1292 idm_nvlist_add_id(nvlist_t
*nvl
, iscsikey_id_t kv_id
, char *value
)
1295 for (i
= 0; i
< KI_MAX_KEY
; i
++) {
1296 if (idm_kvpair_xlate
[i
].ik_key_id
== kv_id
) {
1298 (idm_nvlist_add_kv(nvl
,
1299 &idm_kvpair_xlate
[i
], value
));
1306 idm_id_to_name(iscsikey_id_t kv_id
)
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
);
1318 * return the value in a buffer that must be freed by the caller
1321 idm_nvpair_value_to_textbuf(nvpair_t
*nvp
)
1327 bzero(&itb
, sizeof (itb
));
1328 rv
= idm_itextbuf_add_nvpair(nvp
, &itb
);
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
);
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
);
1344 * build an iscsi text buffer - the memory gets freed in
1348 idm_nvlist_to_itextbuf(nvlist_t
*nvl
)
1352 int validlen
, textbuflen
;
1354 if (idm_nvlist_to_textbuf(nvl
, &textbuf
, &textbuflen
,
1355 &validlen
) != IDM_STATUS_SUCCESS
) {
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
);
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
1373 idm_pdu_init_text_data(idm_pdu_t
*pdu
, void *arg
,
1374 int max_xfer_len
, char *bufptr
, int *transit
)
1376 char *start_ptr
, *end_ptr
, *ptr
;
1377 idm_textbuf_t
*itb
= arg
;
1378 iscsi_hdr_t
*ihp
= pdu
->isp_hdr
;
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
) {
1388 * the entire text buffer fits in the pdu
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
;
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];
1404 len
= (uintptr_t)&itb
->itb_mem
[itb
->itb_offset
] -
1406 if (len
<= max_xfer_len
) {
1408 * the remaining text fits in the pdu
1410 bcopy(bufptr
, pdu
->isp_data
, (size_t)len
);
1411 pdu
->isp_datalen
= len
;
1412 ihp
->flags
&= ~ISCSI_FLAG_TEXT_CONTINUE
;
1416 /* we still have more data then will fit in one pdu */
1418 end_ptr
= &bufptr
[max_xfer_len
- 1];
1420 /* break after key, after =, after the value or after '\0' */
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') {
1429 while (*ptr
!= '\0' && *ptr
!= '=' && ptr
!= start_ptr
) {
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
;
1442 idm_itextbuf_free(void *arg
)
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
));
1451 * Allocate an nvlist and poputlate with key=value from the pdu list.
1452 * NOTE: caller must free the list
1455 idm_pdu_list_to_nvlist(list_t
*pdu_list
, nvlist_t
**nvlist
,
1456 uint8_t *error_detail
)
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;
1463 int split_kvbuflen
, cont_fraglen
;
1464 iscsi_login_hdr_t
*lh
;
1466 int ret
= IDM_STATUS_SUCCESS
;
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
,
1473 *error_detail
= ISCSI_LOGIN_STATUS_NO_RESOURCES
;
1474 ret
= IDM_STATUS_FAIL
;
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.
1484 pdu
= list_head(pdu_list
);
1485 while (pdu
!= NULL
) {
1486 next_pdu
= list_next(pdu_list
, pdu
);
1488 lh
= (iscsi_login_hdr_t
*)pdu
->isp_hdr
;
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
);
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
1508 cont_fraglen
= idm_textbuf_to_firstfraglen(textbuf
,
1510 if (cont_fraglen
== pdu
->isp_datalen
) {
1512 * This key-value pair spans more than two
1513 * PDU's. We don't handle this.
1515 *error_detail
= ISCSI_LOGIN_STATUS_TARGET_ERROR
;
1516 ret
= IDM_STATUS_FAIL
;
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
;
1528 bcopy(leftover_textbuf
, split_kvbuf
,
1529 leftover_textbuflen
);
1531 (uint8_t *)split_kvbuf
+ leftover_textbuflen
,
1535 if (idm_textbuf_to_nvlist(*nvlist
,
1536 &split_kvbuf
, &split_kvbuflen
) != 0) {
1538 * Need to handle E2BIG case, indicating that
1539 * a key-value pair is split across multiple
1542 kmem_free(split_kvbuf
, split_kvbuflen
);
1544 *error_detail
= ISCSI_LOGIN_STATUS_TARGET_ERROR
;
1545 ret
= IDM_STATUS_FAIL
;
1549 ASSERT(split_kvbuflen
!= 0);
1550 kmem_free(split_kvbuf
, split_kvbuflen
);
1552 /* Now handle the remainder of the PDU as normal */
1553 textbuf
+= (cont_fraglen
+ 1);
1554 textbuflen
-= (cont_fraglen
+ 1);
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.
1563 if (idm_textbuf_to_nvlist(*nvlist
,
1564 &textbuf
, &textbuflen
) != 0) {
1566 *error_detail
= ISCSI_LOGIN_STATUS_TARGET_ERROR
;
1567 ret
= IDM_STATUS_FAIL
;
1572 ((lh
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) &&
1573 (next_pdu
!= NULL
)) ||
1574 (!(lh
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) &&
1575 (next_pdu
== NULL
)));
1577 if ((lh
->flags
& ISCSI_FLAG_LOGIN_CONTINUE
) &
1578 (textbuflen
!= 0)) {
1580 * Key-value pair is split over two PDU's. We
1581 * assume it willl never be split over more than
1585 leftover_textbuf
= textbuf
;
1586 leftover_textbuflen
= textbuflen
;
1589 if (textbuflen
!= 0) {
1591 * Incomplete keyword but no additional
1592 * PDU's. This is a malformed login
1596 ISCSI_LOGIN_STATUS_INVALID_REQUEST
;
1597 ret
= IDM_STATUS_FAIL
;
1602 list_remove(pdu_list
, pdu
);
1603 idm_pdu_complete(pdu
, IDM_STATUS_SUCCESS
);
1610 * Free any remaining PDUs on the list. This will only
1611 * happen if there were errors encountered during
1612 * processing of the textbuf.
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
);
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.