17978SPeter.Dunlap@Sun.COM /* 27978SPeter.Dunlap@Sun.COM * CDDL HEADER START 37978SPeter.Dunlap@Sun.COM * 47978SPeter.Dunlap@Sun.COM * The contents of this file are subject to the terms of the 57978SPeter.Dunlap@Sun.COM * Common Development and Distribution License (the "License"). 67978SPeter.Dunlap@Sun.COM * You may not use this file except in compliance with the License. 77978SPeter.Dunlap@Sun.COM * 87978SPeter.Dunlap@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97978SPeter.Dunlap@Sun.COM * or http://www.opensolaris.org/os/licensing. 107978SPeter.Dunlap@Sun.COM * See the License for the specific language governing permissions 117978SPeter.Dunlap@Sun.COM * and limitations under the License. 127978SPeter.Dunlap@Sun.COM * 137978SPeter.Dunlap@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147978SPeter.Dunlap@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157978SPeter.Dunlap@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167978SPeter.Dunlap@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177978SPeter.Dunlap@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187978SPeter.Dunlap@Sun.COM * 197978SPeter.Dunlap@Sun.COM * CDDL HEADER END 207978SPeter.Dunlap@Sun.COM */ 217978SPeter.Dunlap@Sun.COM /* 22*8872SJordan.Vaughan@Sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237978SPeter.Dunlap@Sun.COM * Use is subject to license terms. 247978SPeter.Dunlap@Sun.COM */ 257978SPeter.Dunlap@Sun.COM 267978SPeter.Dunlap@Sun.COM #include <sys/types.h> 277978SPeter.Dunlap@Sun.COM #include <sys/conf.h> 287978SPeter.Dunlap@Sun.COM #include <sys/file.h> 297978SPeter.Dunlap@Sun.COM #include <sys/ddi.h> 307978SPeter.Dunlap@Sun.COM #include <sys/sunddi.h> 317978SPeter.Dunlap@Sun.COM #include <sys/sysmacros.h> 327978SPeter.Dunlap@Sun.COM #include <sys/socket.h> 337978SPeter.Dunlap@Sun.COM 347978SPeter.Dunlap@Sun.COM #include <sys/iscsi_protocol.h> 357978SPeter.Dunlap@Sun.COM #include <sys/idm/idm.h> 367978SPeter.Dunlap@Sun.COM #include <sys/idm/idm_text.h> 377978SPeter.Dunlap@Sun.COM 387978SPeter.Dunlap@Sun.COM 397978SPeter.Dunlap@Sun.COM extern int 407978SPeter.Dunlap@Sun.COM iscsi_base64_str_to_binary(char *hstr, int hstr_len, 417978SPeter.Dunlap@Sun.COM uint8_t *binary, int binary_buf_len, int *out_len); 427978SPeter.Dunlap@Sun.COM 437978SPeter.Dunlap@Sun.COM 447978SPeter.Dunlap@Sun.COM static const char idm_hex_to_ascii[] = "0123456789abcdefABCDEF"; 457978SPeter.Dunlap@Sun.COM 467978SPeter.Dunlap@Sun.COM static const idm_kv_xlate_t idm_kvpair_xlate[] = { 477978SPeter.Dunlap@Sun.COM /* 487978SPeter.Dunlap@Sun.COM * iSCSI Security Text Keys and Authentication Methods 497978SPeter.Dunlap@Sun.COM */ 507978SPeter.Dunlap@Sun.COM 517978SPeter.Dunlap@Sun.COM { KI_AUTH_METHOD, "AuthMethod", KT_LIST_OF_VALUES, B_FALSE }, 527978SPeter.Dunlap@Sun.COM /* 537978SPeter.Dunlap@Sun.COM * For values with RFC comments we need to read the RFC to see 547978SPeter.Dunlap@Sun.COM * what type is appropriate. For now just treat the value as 557978SPeter.Dunlap@Sun.COM * text. 567978SPeter.Dunlap@Sun.COM */ 577978SPeter.Dunlap@Sun.COM 587978SPeter.Dunlap@Sun.COM /* Kerberos */ 597978SPeter.Dunlap@Sun.COM { KI_KRB_AP_REQ, "KRB_AP_REQ", KT_TEXT /* RFC1510 */, B_TRUE}, 607978SPeter.Dunlap@Sun.COM { KI_KRB_AP_REP, "KRB_AP_REP", KT_TEXT /* RFC1510 */, B_TRUE}, 617978SPeter.Dunlap@Sun.COM 627978SPeter.Dunlap@Sun.COM /* SPKM */ 637978SPeter.Dunlap@Sun.COM { KI_SPKM_REQ, "SPKM_REQ", KT_TEXT /* RFC2025 */, B_TRUE}, 647978SPeter.Dunlap@Sun.COM { KI_SPKM_ERROR, "SPKM_ERROR", KT_TEXT /* RFC2025 */, B_TRUE}, 657978SPeter.Dunlap@Sun.COM { KI_SPKM_REP_TI, "SPKM_REP_TI", KT_TEXT /* RFC2025 */, B_TRUE}, 667978SPeter.Dunlap@Sun.COM { KI_SPKM_REP_IT, "SPKM_REP_IT", KT_TEXT /* RFC2025 */, B_TRUE}, 677978SPeter.Dunlap@Sun.COM 687978SPeter.Dunlap@Sun.COM /* 697978SPeter.Dunlap@Sun.COM * SRP 707978SPeter.Dunlap@Sun.COM * U, s, A, B, M, and H(A | M | K) are defined in [RFC2945] 717978SPeter.Dunlap@Sun.COM */ 727978SPeter.Dunlap@Sun.COM { KI_SRP_U, "SRP_U", KT_TEXT /* <U> */, B_TRUE}, 737978SPeter.Dunlap@Sun.COM { KI_TARGET_AUTH, "TargetAuth", KT_BOOLEAN, B_TRUE}, 747978SPeter.Dunlap@Sun.COM { KI_SRP_GROUP, "SRP_GROUP", KT_LIST_OF_VALUES /* <G1,..> */, B_FALSE}, 757978SPeter.Dunlap@Sun.COM { KI_SRP_A, "SRP_A", KT_TEXT /* <A> */, B_TRUE}, 767978SPeter.Dunlap@Sun.COM { KI_SRP_B, "SRP_B", KT_TEXT /* <B> */, B_TRUE}, 777978SPeter.Dunlap@Sun.COM { KI_SRP_M, "SRP_M", KT_TEXT /* <M> */, B_TRUE}, 787978SPeter.Dunlap@Sun.COM { KI_SRM_HM, "SRP_HM", KT_TEXT /* <H(A | M | K)> */, B_TRUE}, 797978SPeter.Dunlap@Sun.COM 807978SPeter.Dunlap@Sun.COM /* 817978SPeter.Dunlap@Sun.COM * CHAP 827978SPeter.Dunlap@Sun.COM */ 837978SPeter.Dunlap@Sun.COM { KI_CHAP_A, "CHAP_A", KT_LIST_OF_VALUES /* <A1,A2,..> */, B_FALSE }, 847978SPeter.Dunlap@Sun.COM { KI_CHAP_I, "CHAP_I", KT_NUMERICAL /* <I> */, B_TRUE }, 857978SPeter.Dunlap@Sun.COM { KI_CHAP_C, "CHAP_C", KT_BINARY /* <C> */, B_TRUE }, 867978SPeter.Dunlap@Sun.COM { KI_CHAP_N, "CHAP_N", KT_TEXT /* <N> */, B_TRUE }, 877978SPeter.Dunlap@Sun.COM { KI_CHAP_R, "CHAP_R", KT_BINARY /* <N> */, B_TRUE }, 887978SPeter.Dunlap@Sun.COM 897978SPeter.Dunlap@Sun.COM 907978SPeter.Dunlap@Sun.COM /* 917978SPeter.Dunlap@Sun.COM * ISCSI Operational Parameter Keys 927978SPeter.Dunlap@Sun.COM */ 937978SPeter.Dunlap@Sun.COM { KI_HEADER_DIGEST, "HeaderDigest", KT_LIST_OF_VALUES, B_FALSE }, 947978SPeter.Dunlap@Sun.COM { KI_DATA_DIGEST, "DataDigest", KT_LIST_OF_VALUES, B_FALSE }, 957978SPeter.Dunlap@Sun.COM { KI_MAX_CONNECTIONS, "MaxConnections", KT_NUMERICAL, B_FALSE }, 967978SPeter.Dunlap@Sun.COM { KI_SEND_TARGETS, "SendTargets", KT_TEXT, B_FALSE }, 977978SPeter.Dunlap@Sun.COM { KI_TARGET_NAME, "TargetName", KT_ISCSI_NAME, B_TRUE}, 987978SPeter.Dunlap@Sun.COM { KI_INITIATOR_NAME, "InitiatorName", KT_ISCSI_NAME, B_TRUE}, 997978SPeter.Dunlap@Sun.COM { KI_TARGET_ALIAS, "TargetAlias", KT_ISCSI_LOCAL_NAME, B_TRUE}, 1007978SPeter.Dunlap@Sun.COM { KI_INITIATOR_ALIAS, "InitiatorAlias", KT_ISCSI_LOCAL_NAME, B_TRUE}, 1017978SPeter.Dunlap@Sun.COM { KI_TARGET_ADDRESS, "TargetAddress", KT_TEXT, B_TRUE}, 1027978SPeter.Dunlap@Sun.COM { KI_TARGET_PORTAL_GROUP_TAG, "TargetPortalGroupTag", 1037978SPeter.Dunlap@Sun.COM KT_NUMERICAL, B_TRUE }, 1047978SPeter.Dunlap@Sun.COM { KI_INITIAL_R2T, "InitialR2T", KT_BOOLEAN, B_FALSE }, 1057978SPeter.Dunlap@Sun.COM { KI_IMMEDIATE_DATA, "ImmediateData", KT_BOOLEAN, B_FALSE }, 1067978SPeter.Dunlap@Sun.COM { KI_MAX_RECV_DATA_SEGMENT_LENGTH, "MaxRecvDataSegmentLength", 1077978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 512 to 2^24 - 1 */, B_TRUE }, 1087978SPeter.Dunlap@Sun.COM { KI_MAX_BURST_LENGTH, "MaxBurstLength", 1097978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE }, 1107978SPeter.Dunlap@Sun.COM { KI_FIRST_BURST_LENGTH, "FirstBurstLength", 1117978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE }, 1127978SPeter.Dunlap@Sun.COM { KI_DEFAULT_TIME_2_WAIT, "DefaultTime2Wait", 1137978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 0 to 2600 */, B_FALSE }, 1147978SPeter.Dunlap@Sun.COM { KI_DEFAULT_TIME_2_RETAIN, "DefaultTime2Retain", 1157978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 0 to 2600 */, B_FALSE }, 1167978SPeter.Dunlap@Sun.COM { KI_MAX_OUTSTANDING_R2T, "MaxOutstandingR2T", 1177978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 1 to 65535 */, B_FALSE }, 1187978SPeter.Dunlap@Sun.COM { KI_DATA_PDU_IN_ORDER, "DataPDUInOrder", KT_BOOLEAN, B_FALSE }, 1197978SPeter.Dunlap@Sun.COM { KI_DATA_SEQUENCE_IN_ORDER, "DataSequenceInOrder", 1207978SPeter.Dunlap@Sun.COM KT_BOOLEAN, B_FALSE }, 1217978SPeter.Dunlap@Sun.COM { KI_ERROR_RECOVERY_LEVEL, "ErrorRecoveryLevel", 1227978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 0 to 2 */, B_FALSE }, 1237978SPeter.Dunlap@Sun.COM { KI_SESSION_TYPE, "SessionType", KT_TEXT, B_TRUE }, 1247978SPeter.Dunlap@Sun.COM { KI_OFMARKER, "OFMarker", KT_BOOLEAN, B_FALSE }, 1257978SPeter.Dunlap@Sun.COM { KI_OFMARKERINT, "OFMarkerInt", KT_NUMERIC_RANGE, B_FALSE }, 1267978SPeter.Dunlap@Sun.COM { KI_IFMARKER, "IFMarker", KT_BOOLEAN, B_FALSE }, 1277978SPeter.Dunlap@Sun.COM { KI_IFMARKERINT, "IFMarkerInt", KT_NUMERIC_RANGE, B_FALSE }, 1287978SPeter.Dunlap@Sun.COM 1297978SPeter.Dunlap@Sun.COM /* 1307978SPeter.Dunlap@Sun.COM * iSER-specific keys 1317978SPeter.Dunlap@Sun.COM */ 1327978SPeter.Dunlap@Sun.COM { KI_RDMA_EXTENSIONS, "RDMAExtensions", KT_BOOLEAN, B_FALSE }, 1337978SPeter.Dunlap@Sun.COM { KI_TARGET_RECV_DATA_SEGMENT_LENGTH, "TargetRecvDataSegmentLength", 1347978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE }, 1357978SPeter.Dunlap@Sun.COM { KI_INITIATOR_RECV_DATA_SEGMENT_LENGTH, 1367978SPeter.Dunlap@Sun.COM "InitiatorRecvDataSegmentLength", 1377978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 512 to 2^24 - 1 */, B_FALSE }, 1387978SPeter.Dunlap@Sun.COM { KI_MAX_OUTSTANDING_UNEXPECTED_PDUS, "MaxOutstandingUnexpectedPDUs", 1397978SPeter.Dunlap@Sun.COM KT_NUMERICAL /* 2 to 2^32 - 1 | 0 */, B_TRUE }, 1407978SPeter.Dunlap@Sun.COM 1417978SPeter.Dunlap@Sun.COM /* 1427978SPeter.Dunlap@Sun.COM * Table terminator. The type KT_TEXT will allow the response 1437978SPeter.Dunlap@Sun.COM * value of "NotUnderstood". 1447978SPeter.Dunlap@Sun.COM */ 1457978SPeter.Dunlap@Sun.COM { KI_MAX_KEY, NULL, KT_TEXT, B_TRUE } /* Terminator */ 1467978SPeter.Dunlap@Sun.COM }; 1477978SPeter.Dunlap@Sun.COM 1487978SPeter.Dunlap@Sun.COM 1497978SPeter.Dunlap@Sun.COM #define TEXTBUF_CHUNKSIZE 8192 1507978SPeter.Dunlap@Sun.COM 1517978SPeter.Dunlap@Sun.COM typedef struct { 1527978SPeter.Dunlap@Sun.COM char *itb_mem; 1537978SPeter.Dunlap@Sun.COM int itb_offset; 1547978SPeter.Dunlap@Sun.COM int itb_mem_len; 1557978SPeter.Dunlap@Sun.COM } idm_textbuf_t; 1567978SPeter.Dunlap@Sun.COM 1577978SPeter.Dunlap@Sun.COM /* 1587978SPeter.Dunlap@Sun.COM * Ignore all but the following keys during security negotiation 1597978SPeter.Dunlap@Sun.COM * 1607978SPeter.Dunlap@Sun.COM * SessionType 1617978SPeter.Dunlap@Sun.COM * InitiatorName 1627978SPeter.Dunlap@Sun.COM * TargetName 1637978SPeter.Dunlap@Sun.COM * TargetAddress 1647978SPeter.Dunlap@Sun.COM * InitiatorAlias 1657978SPeter.Dunlap@Sun.COM * TargetAlias 1667978SPeter.Dunlap@Sun.COM * TargetPortalGroupTag 1677978SPeter.Dunlap@Sun.COM * AuthMethod and associated auth keys 1687978SPeter.Dunlap@Sun.COM */ 1697978SPeter.Dunlap@Sun.COM 1707978SPeter.Dunlap@Sun.COM static int idm_keyvalue_get_next(char **tb_scan, int *tb_len, 1717978SPeter.Dunlap@Sun.COM char **key, int *keylen, char **value); 1727978SPeter.Dunlap@Sun.COM 1737978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_kv(nvlist_t *nvl, const idm_kv_xlate_t *ikvx, 1747978SPeter.Dunlap@Sun.COM char *value); 1757978SPeter.Dunlap@Sun.COM 1767978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_string(nvlist_t *nvl, 1777978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1787978SPeter.Dunlap@Sun.COM 1797978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_boolean(nvlist_t *nvl, 1807978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1817978SPeter.Dunlap@Sun.COM 1827978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_binary(nvlist_t *nvl, 1837978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1847978SPeter.Dunlap@Sun.COM 1857978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_large_numerical(nvlist_t *nvl, 1867978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1877978SPeter.Dunlap@Sun.COM 1887978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_numerical(nvlist_t *nvl, 1897978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1907978SPeter.Dunlap@Sun.COM 1917978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_numeric_range(nvlist_t *nvl, 1927978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1937978SPeter.Dunlap@Sun.COM 1947978SPeter.Dunlap@Sun.COM static int idm_nvlist_add_list_of_values(nvlist_t *nvl, 1957978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value); 1967978SPeter.Dunlap@Sun.COM 1977978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_nvpair(nvpair_t *nvp, idm_textbuf_t *itb); 1987978SPeter.Dunlap@Sun.COM 1997978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_string(nvpair_t *nvp, 2007978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2017978SPeter.Dunlap@Sun.COM 2027978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_boolean(nvpair_t *nvp, 2037978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2047978SPeter.Dunlap@Sun.COM 2057978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_binary(nvpair_t *nvp, 2067978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2077978SPeter.Dunlap@Sun.COM 2087978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_large_numerical(nvpair_t *nvp, 2097978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2107978SPeter.Dunlap@Sun.COM 2117978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_numerical(nvpair_t *nvp, 2127978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2137978SPeter.Dunlap@Sun.COM 2147978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_numeric_range(nvpair_t *nvp, 2157978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2167978SPeter.Dunlap@Sun.COM 2177978SPeter.Dunlap@Sun.COM static int idm_itextbuf_add_list_of_values(nvpair_t *nvp, 2187978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb); 2197978SPeter.Dunlap@Sun.COM 2207978SPeter.Dunlap@Sun.COM static void textbuf_memcpy(idm_textbuf_t *itb, void *mem, int mem_len); 2217978SPeter.Dunlap@Sun.COM 2227978SPeter.Dunlap@Sun.COM static void textbuf_strcpy(idm_textbuf_t *itb, char *str); 2237978SPeter.Dunlap@Sun.COM 2247978SPeter.Dunlap@Sun.COM static void textbuf_append_char(idm_textbuf_t *itb, char c); 2257978SPeter.Dunlap@Sun.COM 2267978SPeter.Dunlap@Sun.COM static void textbuf_terminate_kvpair(idm_textbuf_t *itb); 2277978SPeter.Dunlap@Sun.COM 2287978SPeter.Dunlap@Sun.COM static int idm_ascii_to_hex(char *enc_hex_byte, uint8_t *bin_val); 2297978SPeter.Dunlap@Sun.COM 2307978SPeter.Dunlap@Sun.COM static int idm_base16_str_to_binary(char *hstr, int hstr_len, 2317978SPeter.Dunlap@Sun.COM uint8_t *binary, int binary_length); 2327978SPeter.Dunlap@Sun.COM 2337978SPeter.Dunlap@Sun.COM static size_t idm_strcspn(const char *string, const char *charset); 2347978SPeter.Dunlap@Sun.COM 2357978SPeter.Dunlap@Sun.COM static size_t idm_strnlen(const char *str, size_t maxlen); 2367978SPeter.Dunlap@Sun.COM 2377978SPeter.Dunlap@Sun.COM /* 2387978SPeter.Dunlap@Sun.COM * Processes all whole iSCSI name-value pairs in a text buffer and adds 2397978SPeter.Dunlap@Sun.COM * a corresponding Solaris nvpair_t to the provided nvlist. If the last 2407978SPeter.Dunlap@Sun.COM * iSCSI name-value pair in textbuf is truncated (which can occur when 2417978SPeter.Dunlap@Sun.COM * the request spans multiple PDU's) then upon return textbuf will 2427978SPeter.Dunlap@Sun.COM * point to the truncated iSCSI name-value pair in the buffer and 2437978SPeter.Dunlap@Sun.COM * textbuflen will contain the remaining bytes in the buffer. The 2447978SPeter.Dunlap@Sun.COM * caller can save off this fragment of the iSCSI name-value pair for 2457978SPeter.Dunlap@Sun.COM * use when the next PDU in the request arrives. 2467978SPeter.Dunlap@Sun.COM * 2477978SPeter.Dunlap@Sun.COM * textbuflen includes the trailing 0x00! 2487978SPeter.Dunlap@Sun.COM */ 2497978SPeter.Dunlap@Sun.COM 2507978SPeter.Dunlap@Sun.COM int 2517978SPeter.Dunlap@Sun.COM idm_textbuf_to_nvlist(nvlist_t *nvl, char **textbuf, int *textbuflen) 2527978SPeter.Dunlap@Sun.COM { 2537978SPeter.Dunlap@Sun.COM int rc = 0; 2547978SPeter.Dunlap@Sun.COM char *tbscan, *key, *value; 2557978SPeter.Dunlap@Sun.COM int tblen, keylen; 2567978SPeter.Dunlap@Sun.COM 2577978SPeter.Dunlap@Sun.COM tbscan = *textbuf; 2587978SPeter.Dunlap@Sun.COM tblen = *textbuflen; 2597978SPeter.Dunlap@Sun.COM 2607978SPeter.Dunlap@Sun.COM for (;;) { 2617978SPeter.Dunlap@Sun.COM if ((rc = idm_keyvalue_get_next(&tbscan, &tblen, 2627978SPeter.Dunlap@Sun.COM &key, &keylen, &value)) != 0) { 2637978SPeter.Dunlap@Sun.COM /* There was a problem reading the key/value pair */ 2647978SPeter.Dunlap@Sun.COM break; 2657978SPeter.Dunlap@Sun.COM } 2667978SPeter.Dunlap@Sun.COM 2677978SPeter.Dunlap@Sun.COM if ((rc = idm_nvlist_add_keyvalue(nvl, 2687978SPeter.Dunlap@Sun.COM key, keylen, value)) != 0) { 2697978SPeter.Dunlap@Sun.COM /* Something was wrong with either the key or value */ 2707978SPeter.Dunlap@Sun.COM break; 2717978SPeter.Dunlap@Sun.COM } 2727978SPeter.Dunlap@Sun.COM 2737978SPeter.Dunlap@Sun.COM if (tblen == 0) { 2747978SPeter.Dunlap@Sun.COM /* End of text buffer */ 2757978SPeter.Dunlap@Sun.COM break; 2767978SPeter.Dunlap@Sun.COM } 2777978SPeter.Dunlap@Sun.COM } 2787978SPeter.Dunlap@Sun.COM 2797978SPeter.Dunlap@Sun.COM *textbuf = tbscan; 2807978SPeter.Dunlap@Sun.COM *textbuflen = tblen; 2817978SPeter.Dunlap@Sun.COM 2827978SPeter.Dunlap@Sun.COM return (rc); 2837978SPeter.Dunlap@Sun.COM } 2847978SPeter.Dunlap@Sun.COM 2857978SPeter.Dunlap@Sun.COM /* 2867978SPeter.Dunlap@Sun.COM * If a test buffer starts with an ISCSI name-value pair fragment (a 2877978SPeter.Dunlap@Sun.COM * continuation from a previous buffer) return the length of the fragment 2887978SPeter.Dunlap@Sun.COM * contained in this buffer. We do not handle name-value pairs that span 2897978SPeter.Dunlap@Sun.COM * more than two buffers so if this buffer does not contain the remainder 2907978SPeter.Dunlap@Sun.COM * of the name value pair the function will return 0. If the first 2917978SPeter.Dunlap@Sun.COM * name-value pair in the buffer is complete the functionw will return 0. 2927978SPeter.Dunlap@Sun.COM */ 2937978SPeter.Dunlap@Sun.COM int 2947978SPeter.Dunlap@Sun.COM idm_textbuf_to_firstfraglen(void *textbuf, int textbuflen) 2957978SPeter.Dunlap@Sun.COM { 2967978SPeter.Dunlap@Sun.COM return (idm_strnlen(textbuf, textbuflen)); 2977978SPeter.Dunlap@Sun.COM } 2987978SPeter.Dunlap@Sun.COM 2997978SPeter.Dunlap@Sun.COM static int 3007978SPeter.Dunlap@Sun.COM idm_keyvalue_get_next(char **tb_scan, int *tb_len, 3017978SPeter.Dunlap@Sun.COM char **key, int *keylen, char **value) 3027978SPeter.Dunlap@Sun.COM { 3037978SPeter.Dunlap@Sun.COM /* 3047978SPeter.Dunlap@Sun.COM * Caller doesn't need "valuelen" returned since "value" will 3057978SPeter.Dunlap@Sun.COM * always be a NULL-terminated string. 3067978SPeter.Dunlap@Sun.COM */ 3077978SPeter.Dunlap@Sun.COM size_t total_len, valuelen; 3087978SPeter.Dunlap@Sun.COM 3097978SPeter.Dunlap@Sun.COM /* 3107978SPeter.Dunlap@Sun.COM * How many bytes to the first '\0'? This represents the total 3117978SPeter.Dunlap@Sun.COM * length of our iSCSI key/value pair. 3127978SPeter.Dunlap@Sun.COM */ 3137978SPeter.Dunlap@Sun.COM total_len = idm_strnlen(*tb_scan, *tb_len); 3147978SPeter.Dunlap@Sun.COM if (total_len == *tb_len) { 3157978SPeter.Dunlap@Sun.COM /* 3167978SPeter.Dunlap@Sun.COM * No '\0', perhaps this key/value pair is continued in 3177978SPeter.Dunlap@Sun.COM * another buffer 3187978SPeter.Dunlap@Sun.COM */ 3197978SPeter.Dunlap@Sun.COM return (E2BIG); 3207978SPeter.Dunlap@Sun.COM } 3217978SPeter.Dunlap@Sun.COM 3227978SPeter.Dunlap@Sun.COM /* 3237978SPeter.Dunlap@Sun.COM * Found NULL, so this is a possible key-value pair. At 3247978SPeter.Dunlap@Sun.COM * the same time we've validated that there is actually a 3257978SPeter.Dunlap@Sun.COM * NULL in this string so it's safe to use regular 3267978SPeter.Dunlap@Sun.COM * string functions (i.e. strcpy instead of strncpy) 3277978SPeter.Dunlap@Sun.COM */ 3287978SPeter.Dunlap@Sun.COM *key = *tb_scan; 3297978SPeter.Dunlap@Sun.COM *keylen = idm_strcspn(*tb_scan, "="); 3307978SPeter.Dunlap@Sun.COM 3317978SPeter.Dunlap@Sun.COM if (*keylen == total_len) { 3327978SPeter.Dunlap@Sun.COM /* No '=', bad format */ 3337978SPeter.Dunlap@Sun.COM return (EINVAL); 3347978SPeter.Dunlap@Sun.COM } 3357978SPeter.Dunlap@Sun.COM 3367978SPeter.Dunlap@Sun.COM *tb_scan += *keylen + 1; /* Skip the '=' */ 3377978SPeter.Dunlap@Sun.COM *tb_len -= *keylen + 1; 3387978SPeter.Dunlap@Sun.COM 3397978SPeter.Dunlap@Sun.COM /* 3407978SPeter.Dunlap@Sun.COM * The remaining text after the '=' is the value 3417978SPeter.Dunlap@Sun.COM */ 3427978SPeter.Dunlap@Sun.COM *value = *tb_scan; 3437978SPeter.Dunlap@Sun.COM valuelen = total_len - (*keylen + 1); 3447978SPeter.Dunlap@Sun.COM 3457978SPeter.Dunlap@Sun.COM *tb_scan += valuelen + 1; /* Skip the '\0' */ 3467978SPeter.Dunlap@Sun.COM *tb_len -= valuelen + 1; 3477978SPeter.Dunlap@Sun.COM 3487978SPeter.Dunlap@Sun.COM return (0); 3497978SPeter.Dunlap@Sun.COM } 3507978SPeter.Dunlap@Sun.COM 3517978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t * 3527978SPeter.Dunlap@Sun.COM idm_lookup_kv_xlate(const char *key, int keylen) 3537978SPeter.Dunlap@Sun.COM { 3547978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx = &idm_kvpair_xlate[0]; 3557978SPeter.Dunlap@Sun.COM 3567978SPeter.Dunlap@Sun.COM /* 3577978SPeter.Dunlap@Sun.COM * Look for a matching key value in the key/value pair table. 3587978SPeter.Dunlap@Sun.COM * The matching entry in the table will tell us how to encode 3597978SPeter.Dunlap@Sun.COM * the key and value in the nvlist. If we don't recognize 3607978SPeter.Dunlap@Sun.COM * the key then we will simply encode it in string format. 3617978SPeter.Dunlap@Sun.COM * The login or text request code can generate the appropriate 3627978SPeter.Dunlap@Sun.COM * "not understood" resposne. 3637978SPeter.Dunlap@Sun.COM */ 3647978SPeter.Dunlap@Sun.COM while (ikvx->ik_key_id != KI_MAX_KEY) { 3657978SPeter.Dunlap@Sun.COM /* 3667978SPeter.Dunlap@Sun.COM * Compare strings. "key" is not NULL-terminated so 3677978SPeter.Dunlap@Sun.COM * use strncmp. Since we are using strncmp we 3687978SPeter.Dunlap@Sun.COM * need to check that the lengths match, otherwise 3697978SPeter.Dunlap@Sun.COM * we might unintentionally lookup "TargetAddress" 3707978SPeter.Dunlap@Sun.COM * with a key of "Target" (or something similar). 3717978SPeter.Dunlap@Sun.COM * 3727978SPeter.Dunlap@Sun.COM * "value" is NULL-terminated so we can use it as 3737978SPeter.Dunlap@Sun.COM * a regular string. 3747978SPeter.Dunlap@Sun.COM */ 3757978SPeter.Dunlap@Sun.COM if ((strncmp(ikvx->ik_key_name, key, keylen) == 0) && 3767978SPeter.Dunlap@Sun.COM (strlen(ikvx->ik_key_name) == keylen)) { 3777978SPeter.Dunlap@Sun.COM /* Exit the loop since we found a match */ 3787978SPeter.Dunlap@Sun.COM break; 3797978SPeter.Dunlap@Sun.COM } 3807978SPeter.Dunlap@Sun.COM 3817978SPeter.Dunlap@Sun.COM /* No match, look at the next entry */ 3827978SPeter.Dunlap@Sun.COM ikvx++; 3837978SPeter.Dunlap@Sun.COM } 3847978SPeter.Dunlap@Sun.COM 3857978SPeter.Dunlap@Sun.COM return (ikvx); 3867978SPeter.Dunlap@Sun.COM } 3877978SPeter.Dunlap@Sun.COM 3887978SPeter.Dunlap@Sun.COM static int 3897978SPeter.Dunlap@Sun.COM idm_nvlist_add_kv(nvlist_t *nvl, const idm_kv_xlate_t *ikvx, char *value) 3907978SPeter.Dunlap@Sun.COM { 3917978SPeter.Dunlap@Sun.COM int rc; 3927978SPeter.Dunlap@Sun.COM 3937978SPeter.Dunlap@Sun.COM switch (ikvx->ik_idm_type) { 3947978SPeter.Dunlap@Sun.COM case KT_TEXT: 3957978SPeter.Dunlap@Sun.COM case KT_SIMPLE: 3967978SPeter.Dunlap@Sun.COM case KT_ISCSI_NAME: 3977978SPeter.Dunlap@Sun.COM case KT_ISCSI_LOCAL_NAME: 3987978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_string(nvl, ikvx, value); 3997978SPeter.Dunlap@Sun.COM break; 4007978SPeter.Dunlap@Sun.COM case KT_BOOLEAN: 4017978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_boolean(nvl, ikvx, value); 4027978SPeter.Dunlap@Sun.COM break; 4037978SPeter.Dunlap@Sun.COM case KT_REGULAR_BINARY: 4047978SPeter.Dunlap@Sun.COM case KT_LARGE_BINARY: 4057978SPeter.Dunlap@Sun.COM case KT_BINARY: 4067978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_binary(nvl, ikvx, value); 4077978SPeter.Dunlap@Sun.COM break; 4087978SPeter.Dunlap@Sun.COM case KT_LARGE_NUMERICAL: 4097978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_large_numerical(nvl, ikvx, 4107978SPeter.Dunlap@Sun.COM value); 4117978SPeter.Dunlap@Sun.COM break; 4127978SPeter.Dunlap@Sun.COM case KT_NUMERICAL: 4137978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_numerical(nvl, ikvx, 4147978SPeter.Dunlap@Sun.COM value); 4157978SPeter.Dunlap@Sun.COM break; 4167978SPeter.Dunlap@Sun.COM case KT_NUMERIC_RANGE: 4177978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_numeric_range(nvl, ikvx, 4187978SPeter.Dunlap@Sun.COM value); 4197978SPeter.Dunlap@Sun.COM break; 4207978SPeter.Dunlap@Sun.COM case KT_LIST_OF_VALUES: 4217978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_list_of_values(nvl, ikvx, 4227978SPeter.Dunlap@Sun.COM value); 4237978SPeter.Dunlap@Sun.COM break; 4247978SPeter.Dunlap@Sun.COM default: 4257978SPeter.Dunlap@Sun.COM ASSERT(0); /* This should never happen */ 4267978SPeter.Dunlap@Sun.COM break; 4277978SPeter.Dunlap@Sun.COM } 4287978SPeter.Dunlap@Sun.COM if (rc != 0) { 4297978SPeter.Dunlap@Sun.COM /* could be one of the text constants */ 4307978SPeter.Dunlap@Sun.COM rc = idm_nvlist_add_string(nvl, ikvx, value); 4317978SPeter.Dunlap@Sun.COM } 4327978SPeter.Dunlap@Sun.COM 4337978SPeter.Dunlap@Sun.COM return (rc); 4347978SPeter.Dunlap@Sun.COM } 4357978SPeter.Dunlap@Sun.COM 4367978SPeter.Dunlap@Sun.COM static int 4377978SPeter.Dunlap@Sun.COM idm_nvlist_add_string(nvlist_t *nvl, 4387978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value) 4397978SPeter.Dunlap@Sun.COM { 4407978SPeter.Dunlap@Sun.COM return (nvlist_add_string(nvl, ikvx->ik_key_name, value)); 4417978SPeter.Dunlap@Sun.COM } 4427978SPeter.Dunlap@Sun.COM 4437978SPeter.Dunlap@Sun.COM static int 4447978SPeter.Dunlap@Sun.COM idm_nvlist_add_boolean(nvlist_t *nvl, 4457978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value) 4467978SPeter.Dunlap@Sun.COM { 4477978SPeter.Dunlap@Sun.COM int rc; 4487978SPeter.Dunlap@Sun.COM boolean_t bool_val; 4497978SPeter.Dunlap@Sun.COM 4507978SPeter.Dunlap@Sun.COM if (strcasecmp(value, "Yes") == 0) { 4517978SPeter.Dunlap@Sun.COM bool_val = B_TRUE; 4527978SPeter.Dunlap@Sun.COM } else if (strcasecmp(value, "No") == 0) { 4537978SPeter.Dunlap@Sun.COM bool_val = B_FALSE; 4547978SPeter.Dunlap@Sun.COM } else { 4557978SPeter.Dunlap@Sun.COM return (EINVAL); 4567978SPeter.Dunlap@Sun.COM } 4577978SPeter.Dunlap@Sun.COM 4587978SPeter.Dunlap@Sun.COM rc = nvlist_add_boolean_value(nvl, ikvx->ik_key_name, bool_val); 4597978SPeter.Dunlap@Sun.COM 4607978SPeter.Dunlap@Sun.COM return (rc); 4617978SPeter.Dunlap@Sun.COM } 4627978SPeter.Dunlap@Sun.COM 4637978SPeter.Dunlap@Sun.COM static boolean_t 4647978SPeter.Dunlap@Sun.COM kv_is_hex(char *value) 4657978SPeter.Dunlap@Sun.COM { 4667978SPeter.Dunlap@Sun.COM return ((strncmp(value, "0x", strlen("0x")) == 0) || 4677978SPeter.Dunlap@Sun.COM (strncmp(value, "0X", strlen("0X")) == 0)); 4687978SPeter.Dunlap@Sun.COM } 4697978SPeter.Dunlap@Sun.COM 4707978SPeter.Dunlap@Sun.COM static boolean_t 4717978SPeter.Dunlap@Sun.COM kv_is_base64(char *value) 4727978SPeter.Dunlap@Sun.COM { 4737978SPeter.Dunlap@Sun.COM return ((strncmp(value, "0b", strlen("0b")) == 0) || 4747978SPeter.Dunlap@Sun.COM (strncmp(value, "0B", strlen("0B")) == 0)); 4757978SPeter.Dunlap@Sun.COM } 4767978SPeter.Dunlap@Sun.COM 4777978SPeter.Dunlap@Sun.COM 4787978SPeter.Dunlap@Sun.COM static int 4797978SPeter.Dunlap@Sun.COM idm_nvlist_add_binary(nvlist_t *nvl, 4807978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value) 4817978SPeter.Dunlap@Sun.COM { 4827978SPeter.Dunlap@Sun.COM int rc; 4837978SPeter.Dunlap@Sun.COM int value_length; 4847978SPeter.Dunlap@Sun.COM uint64_t uint64_value; 4857978SPeter.Dunlap@Sun.COM int binary_length; 4867978SPeter.Dunlap@Sun.COM uchar_t *binary_array; 4877978SPeter.Dunlap@Sun.COM 4887978SPeter.Dunlap@Sun.COM /* 4897978SPeter.Dunlap@Sun.COM * A binary value can be either decimal, hex or base64. If it's 4907978SPeter.Dunlap@Sun.COM * decimal then the encoded string must be less than 64 bits in 4917978SPeter.Dunlap@Sun.COM * length (8 characters). In all cases we will convert the 4927978SPeter.Dunlap@Sun.COM * included value to a byte array starting with the MSB. The 4937978SPeter.Dunlap@Sun.COM * assumption is that values meant to be treated as integers will 4947978SPeter.Dunlap@Sun.COM * use the "numerical" and "large numerical" types. 4957978SPeter.Dunlap@Sun.COM */ 4967978SPeter.Dunlap@Sun.COM if (kv_is_hex(value)) { 4977978SPeter.Dunlap@Sun.COM value += strlen("0x"); 4987978SPeter.Dunlap@Sun.COM value_length = strlen(value); 4997978SPeter.Dunlap@Sun.COM binary_length = (value_length + 1) / 2; 5007978SPeter.Dunlap@Sun.COM binary_array = kmem_alloc(binary_length, KM_SLEEP); 5017978SPeter.Dunlap@Sun.COM 5027978SPeter.Dunlap@Sun.COM if (idm_base16_str_to_binary(value, value_length, 5037978SPeter.Dunlap@Sun.COM binary_array, binary_length) != 0) { 5047978SPeter.Dunlap@Sun.COM kmem_free(binary_array, binary_length); 5057978SPeter.Dunlap@Sun.COM return (EINVAL); 5067978SPeter.Dunlap@Sun.COM } 5077978SPeter.Dunlap@Sun.COM 5087978SPeter.Dunlap@Sun.COM rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name, 5097978SPeter.Dunlap@Sun.COM binary_array, binary_length); 5107978SPeter.Dunlap@Sun.COM 5117978SPeter.Dunlap@Sun.COM kmem_free(binary_array, binary_length); 5127978SPeter.Dunlap@Sun.COM 5137978SPeter.Dunlap@Sun.COM return (rc); 5147978SPeter.Dunlap@Sun.COM 5157978SPeter.Dunlap@Sun.COM } else if (kv_is_base64(value)) { 5167978SPeter.Dunlap@Sun.COM value += strlen("0b"); 5177978SPeter.Dunlap@Sun.COM value_length = strlen(value); 5187978SPeter.Dunlap@Sun.COM binary_array = kmem_alloc(value_length, KM_NOSLEEP); 5197978SPeter.Dunlap@Sun.COM if (binary_array == NULL) { 5207978SPeter.Dunlap@Sun.COM return (ENOMEM); 5217978SPeter.Dunlap@Sun.COM } 5227978SPeter.Dunlap@Sun.COM 5237978SPeter.Dunlap@Sun.COM if (iscsi_base64_str_to_binary(value, value_length, 5247978SPeter.Dunlap@Sun.COM binary_array, value_length, &binary_length) != 0) { 5257978SPeter.Dunlap@Sun.COM kmem_free(binary_array, value_length); 5267978SPeter.Dunlap@Sun.COM return (EINVAL); 5277978SPeter.Dunlap@Sun.COM } 5287978SPeter.Dunlap@Sun.COM 5297978SPeter.Dunlap@Sun.COM rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name, 5307978SPeter.Dunlap@Sun.COM binary_array, binary_length); 5317978SPeter.Dunlap@Sun.COM 5327978SPeter.Dunlap@Sun.COM kmem_free(binary_array, value_length); 5337978SPeter.Dunlap@Sun.COM 5347978SPeter.Dunlap@Sun.COM return (rc); 5357978SPeter.Dunlap@Sun.COM } else { 5367978SPeter.Dunlap@Sun.COM /* 5377978SPeter.Dunlap@Sun.COM * Decimal value (not permitted for "large-binary_value" so 5387978SPeter.Dunlap@Sun.COM * it must be smaller than 64 bits. It's not really 5397978SPeter.Dunlap@Sun.COM * clear from the RFC what a decimal-binary-value might 5407978SPeter.Dunlap@Sun.COM * represent but presumably it should be treated the same 5417978SPeter.Dunlap@Sun.COM * as a hex or base64 value. Therefore we'll convert it 5427978SPeter.Dunlap@Sun.COM * to an array of bytes. 5437978SPeter.Dunlap@Sun.COM */ 544*8872SJordan.Vaughan@Sun.com if ((rc = ddi_strtoull(value, NULL, 0, 5457978SPeter.Dunlap@Sun.COM (u_longlong_t *)&uint64_value)) != 0) 5467978SPeter.Dunlap@Sun.COM return (rc); 5477978SPeter.Dunlap@Sun.COM 5487978SPeter.Dunlap@Sun.COM rc = nvlist_add_byte_array(nvl, ikvx->ik_key_name, 5497978SPeter.Dunlap@Sun.COM (uint8_t *)&uint64_value, sizeof (uint64_value)); 5507978SPeter.Dunlap@Sun.COM 5517978SPeter.Dunlap@Sun.COM return (rc); 5527978SPeter.Dunlap@Sun.COM } 5537978SPeter.Dunlap@Sun.COM 5547978SPeter.Dunlap@Sun.COM /* NOTREACHED */ 5557978SPeter.Dunlap@Sun.COM } 5567978SPeter.Dunlap@Sun.COM 5577978SPeter.Dunlap@Sun.COM 5587978SPeter.Dunlap@Sun.COM static int 5597978SPeter.Dunlap@Sun.COM idm_nvlist_add_large_numerical(nvlist_t *nvl, 5607978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value) 5617978SPeter.Dunlap@Sun.COM { 5627978SPeter.Dunlap@Sun.COM /* 5637978SPeter.Dunlap@Sun.COM * A "large numerical" value can be larger than 64-bits. Since 5647978SPeter.Dunlap@Sun.COM * there is no upper bound on the size of the value, we will 5657978SPeter.Dunlap@Sun.COM * punt and store it in string form. We could also potentially 5667978SPeter.Dunlap@Sun.COM * treat the value as binary data. 5677978SPeter.Dunlap@Sun.COM */ 5687978SPeter.Dunlap@Sun.COM return (nvlist_add_string(nvl, ikvx->ik_key_name, value)); 5697978SPeter.Dunlap@Sun.COM } 5707978SPeter.Dunlap@Sun.COM 5717978SPeter.Dunlap@Sun.COM 5727978SPeter.Dunlap@Sun.COM static int 5737978SPeter.Dunlap@Sun.COM idm_nvlist_add_numerical(nvlist_t *nvl, 5747978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value) 5757978SPeter.Dunlap@Sun.COM { 5767978SPeter.Dunlap@Sun.COM int rc; 5777978SPeter.Dunlap@Sun.COM uint64_t uint64_value; 5787978SPeter.Dunlap@Sun.COM 5797978SPeter.Dunlap@Sun.COM /* 5807978SPeter.Dunlap@Sun.COM * "Numerical" values in the iSCSI standard are up to 64-bits wide. 5817978SPeter.Dunlap@Sun.COM * On a 32-bit system we could see an overflow here during conversion. 5827978SPeter.Dunlap@Sun.COM * This shouldn't happen with real-world values for the current 5837978SPeter.Dunlap@Sun.COM * iSCSI parameters of "numerical" type. 5847978SPeter.Dunlap@Sun.COM */ 585*8872SJordan.Vaughan@Sun.com rc = ddi_strtoull(value, NULL, 0, (u_longlong_t *)&uint64_value); 5867978SPeter.Dunlap@Sun.COM if (rc == 0) { 5877978SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(nvl, ikvx->ik_key_name, uint64_value); 5887978SPeter.Dunlap@Sun.COM } 5897978SPeter.Dunlap@Sun.COM 5907978SPeter.Dunlap@Sun.COM return (rc); 5917978SPeter.Dunlap@Sun.COM } 5927978SPeter.Dunlap@Sun.COM 5937978SPeter.Dunlap@Sun.COM 5947978SPeter.Dunlap@Sun.COM static int 5957978SPeter.Dunlap@Sun.COM idm_nvlist_add_numeric_range(nvlist_t *nvl, 5967978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *range) 5977978SPeter.Dunlap@Sun.COM { 5987978SPeter.Dunlap@Sun.COM nvlist_t *range_nvl; 5997978SPeter.Dunlap@Sun.COM char *val_scan = range; 6007978SPeter.Dunlap@Sun.COM uint64_t start_val, end_val; 6017978SPeter.Dunlap@Sun.COM int val_len, range_len; 6027978SPeter.Dunlap@Sun.COM int rc; 6037978SPeter.Dunlap@Sun.COM 6047978SPeter.Dunlap@Sun.COM /* We'll store the range an an nvlist with two values */ 6057978SPeter.Dunlap@Sun.COM rc = nvlist_alloc(&range_nvl, NV_UNIQUE_NAME, KM_NOSLEEP); 6067978SPeter.Dunlap@Sun.COM if (rc != 0) { 6077978SPeter.Dunlap@Sun.COM return (rc); 6087978SPeter.Dunlap@Sun.COM } 6097978SPeter.Dunlap@Sun.COM 6107978SPeter.Dunlap@Sun.COM /* 6117978SPeter.Dunlap@Sun.COM * We expect idm_keyvalue_get_next to ensure the string is 6127978SPeter.Dunlap@Sun.COM * terminated 6137978SPeter.Dunlap@Sun.COM */ 6147978SPeter.Dunlap@Sun.COM range_len = strlen(range); 6157978SPeter.Dunlap@Sun.COM 6167978SPeter.Dunlap@Sun.COM /* 6177978SPeter.Dunlap@Sun.COM * Find range separator 6187978SPeter.Dunlap@Sun.COM */ 6197978SPeter.Dunlap@Sun.COM val_len = idm_strcspn(val_scan, "~"); 6207978SPeter.Dunlap@Sun.COM 6217978SPeter.Dunlap@Sun.COM if (val_len == range_len) { 6227978SPeter.Dunlap@Sun.COM /* invalid range */ 6237978SPeter.Dunlap@Sun.COM nvlist_free(range_nvl); 6247978SPeter.Dunlap@Sun.COM return (EINVAL); 6257978SPeter.Dunlap@Sun.COM } 6267978SPeter.Dunlap@Sun.COM 6277978SPeter.Dunlap@Sun.COM /* 6287978SPeter.Dunlap@Sun.COM * Start value 6297978SPeter.Dunlap@Sun.COM */ 6307978SPeter.Dunlap@Sun.COM *(val_scan + val_len + 1) = '\0'; 631*8872SJordan.Vaughan@Sun.com rc = ddi_strtoull(val_scan, NULL, 0, (u_longlong_t *)&start_val); 6327978SPeter.Dunlap@Sun.COM if (rc == 0) { 6337978SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(range_nvl, "start", start_val); 6347978SPeter.Dunlap@Sun.COM } 6357978SPeter.Dunlap@Sun.COM if (rc != 0) { 6367978SPeter.Dunlap@Sun.COM nvlist_free(range_nvl); 6377978SPeter.Dunlap@Sun.COM return (rc); 6387978SPeter.Dunlap@Sun.COM } 6397978SPeter.Dunlap@Sun.COM 6407978SPeter.Dunlap@Sun.COM /* 6417978SPeter.Dunlap@Sun.COM * End value 6427978SPeter.Dunlap@Sun.COM */ 6437978SPeter.Dunlap@Sun.COM val_scan += val_len + 1; 644*8872SJordan.Vaughan@Sun.com rc = ddi_strtoull(val_scan, NULL, 0, (u_longlong_t *)&end_val); 6457978SPeter.Dunlap@Sun.COM if (rc == 0) { 6467978SPeter.Dunlap@Sun.COM rc = nvlist_add_uint64(range_nvl, "start", end_val); 6477978SPeter.Dunlap@Sun.COM } 6487978SPeter.Dunlap@Sun.COM if (rc != 0) { 6497978SPeter.Dunlap@Sun.COM nvlist_free(range_nvl); 6507978SPeter.Dunlap@Sun.COM return (rc); 6517978SPeter.Dunlap@Sun.COM } 6527978SPeter.Dunlap@Sun.COM 6537978SPeter.Dunlap@Sun.COM /* 6547978SPeter.Dunlap@Sun.COM * Now add the "range" nvlist to the main nvlist 6557978SPeter.Dunlap@Sun.COM */ 6567978SPeter.Dunlap@Sun.COM rc = nvlist_add_nvlist(nvl, ikvx->ik_key_name, range_nvl); 6577978SPeter.Dunlap@Sun.COM if (rc != 0) { 6587978SPeter.Dunlap@Sun.COM nvlist_free(range_nvl); 6597978SPeter.Dunlap@Sun.COM return (rc); 6607978SPeter.Dunlap@Sun.COM } 6617978SPeter.Dunlap@Sun.COM 6627978SPeter.Dunlap@Sun.COM nvlist_free(range_nvl); 6637978SPeter.Dunlap@Sun.COM return (0); 6647978SPeter.Dunlap@Sun.COM } 6657978SPeter.Dunlap@Sun.COM 6667978SPeter.Dunlap@Sun.COM 6677978SPeter.Dunlap@Sun.COM static int 6687978SPeter.Dunlap@Sun.COM idm_nvlist_add_list_of_values(nvlist_t *nvl, 6697978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, char *value_list) 6707978SPeter.Dunlap@Sun.COM { 6717978SPeter.Dunlap@Sun.COM char value_name[8]; 6727978SPeter.Dunlap@Sun.COM nvlist_t *value_list_nvl; 6737978SPeter.Dunlap@Sun.COM char *val_scan = value_list; 6747978SPeter.Dunlap@Sun.COM int value_index = 0; 6757978SPeter.Dunlap@Sun.COM int val_len, val_list_len; 6767978SPeter.Dunlap@Sun.COM int rc; 6777978SPeter.Dunlap@Sun.COM 6787978SPeter.Dunlap@Sun.COM rc = nvlist_alloc(&value_list_nvl, NV_UNIQUE_NAME, KM_NOSLEEP); 6797978SPeter.Dunlap@Sun.COM if (rc != 0) { 6807978SPeter.Dunlap@Sun.COM return (rc); 6817978SPeter.Dunlap@Sun.COM } 6827978SPeter.Dunlap@Sun.COM 6837978SPeter.Dunlap@Sun.COM /* 6847978SPeter.Dunlap@Sun.COM * We expect idm_keyvalue_get_next to ensure the string is 6857978SPeter.Dunlap@Sun.COM * terminated 6867978SPeter.Dunlap@Sun.COM */ 6877978SPeter.Dunlap@Sun.COM val_list_len = strlen(value_list); 6887978SPeter.Dunlap@Sun.COM if (val_list_len == 0) { 6897978SPeter.Dunlap@Sun.COM nvlist_free(value_list_nvl); 6907978SPeter.Dunlap@Sun.COM return (EINVAL); 6917978SPeter.Dunlap@Sun.COM } 6927978SPeter.Dunlap@Sun.COM 6937978SPeter.Dunlap@Sun.COM for (;;) { 6947978SPeter.Dunlap@Sun.COM (void) snprintf(value_name, 8, "value%d", value_index); 6957978SPeter.Dunlap@Sun.COM 6967978SPeter.Dunlap@Sun.COM val_len = idm_strcspn(val_scan, ","); 6977978SPeter.Dunlap@Sun.COM 6987978SPeter.Dunlap@Sun.COM if (*(val_scan + val_len) != '\0') { 6997978SPeter.Dunlap@Sun.COM *(val_scan + val_len) = '\0'; 7007978SPeter.Dunlap@Sun.COM } 7017978SPeter.Dunlap@Sun.COM rc = nvlist_add_string(value_list_nvl, value_name, val_scan); 7027978SPeter.Dunlap@Sun.COM if (rc != 0) { 7037978SPeter.Dunlap@Sun.COM nvlist_free(value_list_nvl); 7047978SPeter.Dunlap@Sun.COM return (rc); 7057978SPeter.Dunlap@Sun.COM } 7067978SPeter.Dunlap@Sun.COM 7077978SPeter.Dunlap@Sun.COM /* 7087978SPeter.Dunlap@Sun.COM * Move to next value, see if we're at the end of the value 7097978SPeter.Dunlap@Sun.COM * list 7107978SPeter.Dunlap@Sun.COM */ 7117978SPeter.Dunlap@Sun.COM val_scan += val_len + 1; 7127978SPeter.Dunlap@Sun.COM if (val_scan == value_list + val_list_len + 1) { 7137978SPeter.Dunlap@Sun.COM break; 7147978SPeter.Dunlap@Sun.COM } 7157978SPeter.Dunlap@Sun.COM 7167978SPeter.Dunlap@Sun.COM value_index++; 7177978SPeter.Dunlap@Sun.COM } 7187978SPeter.Dunlap@Sun.COM 7197978SPeter.Dunlap@Sun.COM rc = nvlist_add_nvlist(nvl, ikvx->ik_key_name, value_list_nvl); 7207978SPeter.Dunlap@Sun.COM if (rc != 0) { 7217978SPeter.Dunlap@Sun.COM nvlist_free(value_list_nvl); 7227978SPeter.Dunlap@Sun.COM return (rc); 7237978SPeter.Dunlap@Sun.COM } 7247978SPeter.Dunlap@Sun.COM 7257978SPeter.Dunlap@Sun.COM nvlist_free(value_list_nvl); 7267978SPeter.Dunlap@Sun.COM return (0); 7277978SPeter.Dunlap@Sun.COM } 7287978SPeter.Dunlap@Sun.COM 7297978SPeter.Dunlap@Sun.COM /* 7307978SPeter.Dunlap@Sun.COM * Convert an nvlist containing standard iSCSI key names and values into 7317978SPeter.Dunlap@Sun.COM * a text buffer with properly formatted iSCSI key-value pairs ready to 7327978SPeter.Dunlap@Sun.COM * transmit on the wire. *textbuf should be NULL and will be set to point 7337978SPeter.Dunlap@Sun.COM * the resulting text buffer. 7347978SPeter.Dunlap@Sun.COM */ 7357978SPeter.Dunlap@Sun.COM 7367978SPeter.Dunlap@Sun.COM int 7377978SPeter.Dunlap@Sun.COM idm_nvlist_to_textbuf(nvlist_t *nvl, char **textbuf, int *textbuflen, 7387978SPeter.Dunlap@Sun.COM int *validlen) 7397978SPeter.Dunlap@Sun.COM { 7407978SPeter.Dunlap@Sun.COM int rc = 0; 7417978SPeter.Dunlap@Sun.COM nvpair_t *nvp = NULL; 7427978SPeter.Dunlap@Sun.COM idm_textbuf_t itb; 7437978SPeter.Dunlap@Sun.COM 7447978SPeter.Dunlap@Sun.COM bzero(&itb, sizeof (itb)); 7457978SPeter.Dunlap@Sun.COM 7467978SPeter.Dunlap@Sun.COM for (;;) { 7477978SPeter.Dunlap@Sun.COM nvp = nvlist_next_nvpair(nvl, nvp); 7487978SPeter.Dunlap@Sun.COM 7497978SPeter.Dunlap@Sun.COM if (nvp == NULL) { 7507978SPeter.Dunlap@Sun.COM /* Last nvpair in nvlist, we're done */ 7517978SPeter.Dunlap@Sun.COM break; 7527978SPeter.Dunlap@Sun.COM } 7537978SPeter.Dunlap@Sun.COM 7547978SPeter.Dunlap@Sun.COM if ((rc = idm_itextbuf_add_nvpair(nvp, &itb)) != 0) { 7557978SPeter.Dunlap@Sun.COM /* There was a problem building the key/value pair */ 7567978SPeter.Dunlap@Sun.COM break; 7577978SPeter.Dunlap@Sun.COM } 7587978SPeter.Dunlap@Sun.COM } 7597978SPeter.Dunlap@Sun.COM 7607978SPeter.Dunlap@Sun.COM *textbuf = itb.itb_mem; 7617978SPeter.Dunlap@Sun.COM *textbuflen = itb.itb_mem_len; 7627978SPeter.Dunlap@Sun.COM *validlen = itb.itb_offset; 7637978SPeter.Dunlap@Sun.COM 7647978SPeter.Dunlap@Sun.COM return (rc); 7657978SPeter.Dunlap@Sun.COM } 7667978SPeter.Dunlap@Sun.COM 7677978SPeter.Dunlap@Sun.COM static int 7687978SPeter.Dunlap@Sun.COM idm_itextbuf_add_nvpair(nvpair_t *nvp, 7697978SPeter.Dunlap@Sun.COM idm_textbuf_t *itb) 7707978SPeter.Dunlap@Sun.COM { 7717978SPeter.Dunlap@Sun.COM int rc = 0; 7727978SPeter.Dunlap@Sun.COM char *key; 7737978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx; 7747978SPeter.Dunlap@Sun.COM 7757978SPeter.Dunlap@Sun.COM key = nvpair_name(nvp); 7767978SPeter.Dunlap@Sun.COM 7777978SPeter.Dunlap@Sun.COM ikvx = idm_lookup_kv_xlate(key, strlen(key)); 7787978SPeter.Dunlap@Sun.COM 7797978SPeter.Dunlap@Sun.COM /* 7807978SPeter.Dunlap@Sun.COM * Any key supplied by the initiator that is not in our table 7817978SPeter.Dunlap@Sun.COM * will be responded to with the string value "NotUnderstood". 7827978SPeter.Dunlap@Sun.COM * An example is a vendor specific key. 7837978SPeter.Dunlap@Sun.COM */ 7847978SPeter.Dunlap@Sun.COM ASSERT((ikvx->ik_key_id != KI_MAX_KEY) || 7857978SPeter.Dunlap@Sun.COM (nvpair_type(nvp) == DATA_TYPE_STRING)); 7867978SPeter.Dunlap@Sun.COM 7877978SPeter.Dunlap@Sun.COM /* 7887978SPeter.Dunlap@Sun.COM * Look for a matching key value in the key/value pair table. 7897978SPeter.Dunlap@Sun.COM * The matching entry in the table will tell us how to encode 7907978SPeter.Dunlap@Sun.COM * the key and value in the nvlist. 7917978SPeter.Dunlap@Sun.COM */ 7927978SPeter.Dunlap@Sun.COM switch (ikvx->ik_idm_type) { 7937978SPeter.Dunlap@Sun.COM case KT_TEXT: 7947978SPeter.Dunlap@Sun.COM case KT_SIMPLE: 7957978SPeter.Dunlap@Sun.COM case KT_ISCSI_NAME: 7967978SPeter.Dunlap@Sun.COM case KT_ISCSI_LOCAL_NAME: 7977978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_string(nvp, ikvx, itb); 7987978SPeter.Dunlap@Sun.COM break; 7997978SPeter.Dunlap@Sun.COM case KT_BOOLEAN: 8007978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_boolean(nvp, ikvx, itb); 8017978SPeter.Dunlap@Sun.COM break; 8027978SPeter.Dunlap@Sun.COM case KT_REGULAR_BINARY: 8037978SPeter.Dunlap@Sun.COM case KT_LARGE_BINARY: 8047978SPeter.Dunlap@Sun.COM case KT_BINARY: 8057978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_binary(nvp, ikvx, itb); 8067978SPeter.Dunlap@Sun.COM break; 8077978SPeter.Dunlap@Sun.COM case KT_LARGE_NUMERICAL: 8087978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_large_numerical(nvp, ikvx, itb); 8097978SPeter.Dunlap@Sun.COM break; 8107978SPeter.Dunlap@Sun.COM case KT_NUMERICAL: 8117978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_numerical(nvp, ikvx, itb); 8127978SPeter.Dunlap@Sun.COM break; 8137978SPeter.Dunlap@Sun.COM case KT_NUMERIC_RANGE: 8147978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_numeric_range(nvp, ikvx, itb); 8157978SPeter.Dunlap@Sun.COM break; 8167978SPeter.Dunlap@Sun.COM case KT_LIST_OF_VALUES: 8177978SPeter.Dunlap@Sun.COM rc = idm_itextbuf_add_list_of_values(nvp, ikvx, itb); 8187978SPeter.Dunlap@Sun.COM break; 8197978SPeter.Dunlap@Sun.COM default: 8207978SPeter.Dunlap@Sun.COM ASSERT(0); /* This should never happen */ 8217978SPeter.Dunlap@Sun.COM break; 8227978SPeter.Dunlap@Sun.COM } 8237978SPeter.Dunlap@Sun.COM 8247978SPeter.Dunlap@Sun.COM return (rc); 8257978SPeter.Dunlap@Sun.COM } 8267978SPeter.Dunlap@Sun.COM 8277978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 8287978SPeter.Dunlap@Sun.COM static int 8297978SPeter.Dunlap@Sun.COM idm_itextbuf_add_string(nvpair_t *nvp, 8307978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 8317978SPeter.Dunlap@Sun.COM { 8327978SPeter.Dunlap@Sun.COM char *key_name; 8337978SPeter.Dunlap@Sun.COM char *value; 8347978SPeter.Dunlap@Sun.COM int rc; 8357978SPeter.Dunlap@Sun.COM 8367978SPeter.Dunlap@Sun.COM /* Start with the key name */ 8377978SPeter.Dunlap@Sun.COM key_name = nvpair_name(nvp); 8387978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, key_name); 8397978SPeter.Dunlap@Sun.COM 8407978SPeter.Dunlap@Sun.COM /* Add separator */ 8417978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '='); 8427978SPeter.Dunlap@Sun.COM 8437978SPeter.Dunlap@Sun.COM /* Add value */ 8447978SPeter.Dunlap@Sun.COM rc = nvpair_value_string(nvp, &value); 8457978SPeter.Dunlap@Sun.COM ASSERT(rc == 0); 8467978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, value); 8477978SPeter.Dunlap@Sun.COM 8487978SPeter.Dunlap@Sun.COM /* Add trailing 0x00 */ 8497978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(itb); 8507978SPeter.Dunlap@Sun.COM 8517978SPeter.Dunlap@Sun.COM return (0); 8527978SPeter.Dunlap@Sun.COM } 8537978SPeter.Dunlap@Sun.COM 8547978SPeter.Dunlap@Sun.COM 8557978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 8567978SPeter.Dunlap@Sun.COM static int 8577978SPeter.Dunlap@Sun.COM idm_itextbuf_add_boolean(nvpair_t *nvp, 8587978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 8597978SPeter.Dunlap@Sun.COM { 8607978SPeter.Dunlap@Sun.COM char *key_name; 8617978SPeter.Dunlap@Sun.COM boolean_t value; 8627978SPeter.Dunlap@Sun.COM int rc; 8637978SPeter.Dunlap@Sun.COM 8647978SPeter.Dunlap@Sun.COM /* Start with the key name */ 8657978SPeter.Dunlap@Sun.COM key_name = nvpair_name(nvp); 8667978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, key_name); 8677978SPeter.Dunlap@Sun.COM 8687978SPeter.Dunlap@Sun.COM /* Add separator */ 8697978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '='); 8707978SPeter.Dunlap@Sun.COM 8717978SPeter.Dunlap@Sun.COM /* Add value */ 8727978SPeter.Dunlap@Sun.COM rc = nvpair_value_boolean_value(nvp, &value); 8737978SPeter.Dunlap@Sun.COM ASSERT(rc == 0); 8747978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, value ? "Yes" : "No"); 8757978SPeter.Dunlap@Sun.COM 8767978SPeter.Dunlap@Sun.COM /* Add trailing 0x00 */ 8777978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(itb); 8787978SPeter.Dunlap@Sun.COM 8797978SPeter.Dunlap@Sun.COM return (0); 8807978SPeter.Dunlap@Sun.COM } 8817978SPeter.Dunlap@Sun.COM 8827978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 8837978SPeter.Dunlap@Sun.COM static int 8847978SPeter.Dunlap@Sun.COM idm_itextbuf_add_binary(nvpair_t *nvp, 8857978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 8867978SPeter.Dunlap@Sun.COM { 8877978SPeter.Dunlap@Sun.COM char *key_name; 8887978SPeter.Dunlap@Sun.COM unsigned char *value; 8897978SPeter.Dunlap@Sun.COM unsigned int len; 8907978SPeter.Dunlap@Sun.COM unsigned long n; 8917978SPeter.Dunlap@Sun.COM int rc; 8927978SPeter.Dunlap@Sun.COM 8937978SPeter.Dunlap@Sun.COM /* Start with the key name */ 8947978SPeter.Dunlap@Sun.COM key_name = nvpair_name(nvp); 8957978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, key_name); 8967978SPeter.Dunlap@Sun.COM 8977978SPeter.Dunlap@Sun.COM /* Add separator */ 8987978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '='); 8997978SPeter.Dunlap@Sun.COM 9007978SPeter.Dunlap@Sun.COM /* Add value */ 9017978SPeter.Dunlap@Sun.COM rc = nvpair_value_byte_array(nvp, &value, &len); 9027978SPeter.Dunlap@Sun.COM ASSERT(rc == 0); 9037978SPeter.Dunlap@Sun.COM 9047978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, "0x"); 9057978SPeter.Dunlap@Sun.COM 9067978SPeter.Dunlap@Sun.COM while (len > 0) { 9077978SPeter.Dunlap@Sun.COM n = *value++; 9087978SPeter.Dunlap@Sun.COM len--; 9097978SPeter.Dunlap@Sun.COM 9107978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, idm_hex_to_ascii[(n >> 4) & 0xf]); 9117978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, idm_hex_to_ascii[n & 0xf]); 9127978SPeter.Dunlap@Sun.COM } 9137978SPeter.Dunlap@Sun.COM 9147978SPeter.Dunlap@Sun.COM /* Add trailing 0x00 */ 9157978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(itb); 9167978SPeter.Dunlap@Sun.COM 9177978SPeter.Dunlap@Sun.COM return (0); 9187978SPeter.Dunlap@Sun.COM } 9197978SPeter.Dunlap@Sun.COM 9207978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9217978SPeter.Dunlap@Sun.COM static int 9227978SPeter.Dunlap@Sun.COM idm_itextbuf_add_large_numerical(nvpair_t *nvp, 9237978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 9247978SPeter.Dunlap@Sun.COM { 9257978SPeter.Dunlap@Sun.COM ASSERT(0); 9267978SPeter.Dunlap@Sun.COM return (0); 9277978SPeter.Dunlap@Sun.COM } 9287978SPeter.Dunlap@Sun.COM 9297978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9307978SPeter.Dunlap@Sun.COM static int 9317978SPeter.Dunlap@Sun.COM idm_itextbuf_add_numerical(nvpair_t *nvp, 9327978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 9337978SPeter.Dunlap@Sun.COM { 9347978SPeter.Dunlap@Sun.COM char *key_name; 9357978SPeter.Dunlap@Sun.COM uint64_t value; 9367978SPeter.Dunlap@Sun.COM int rc; 9377978SPeter.Dunlap@Sun.COM char str[16]; 9387978SPeter.Dunlap@Sun.COM 9397978SPeter.Dunlap@Sun.COM /* Start with the key name */ 9407978SPeter.Dunlap@Sun.COM key_name = nvpair_name(nvp); 9417978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, key_name); 9427978SPeter.Dunlap@Sun.COM 9437978SPeter.Dunlap@Sun.COM /* Add separator */ 9447978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '='); 9457978SPeter.Dunlap@Sun.COM 9467978SPeter.Dunlap@Sun.COM /* Add value */ 9477978SPeter.Dunlap@Sun.COM rc = nvpair_value_uint64(nvp, &value); 9487978SPeter.Dunlap@Sun.COM ASSERT(rc == 0); 9497978SPeter.Dunlap@Sun.COM (void) sprintf(str, "%llu", (u_longlong_t)value); 9507978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, str); 9517978SPeter.Dunlap@Sun.COM 9527978SPeter.Dunlap@Sun.COM /* Add trailing 0x00 */ 9537978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(itb); 9547978SPeter.Dunlap@Sun.COM 9557978SPeter.Dunlap@Sun.COM return (0); 9567978SPeter.Dunlap@Sun.COM } 9577978SPeter.Dunlap@Sun.COM 9587978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9597978SPeter.Dunlap@Sun.COM static int 9607978SPeter.Dunlap@Sun.COM idm_itextbuf_add_numeric_range(nvpair_t *nvp, 9617978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 9627978SPeter.Dunlap@Sun.COM { 9637978SPeter.Dunlap@Sun.COM ASSERT(0); 9647978SPeter.Dunlap@Sun.COM return (0); 9657978SPeter.Dunlap@Sun.COM } 9667978SPeter.Dunlap@Sun.COM 9677978SPeter.Dunlap@Sun.COM /* ARGSUSED */ 9687978SPeter.Dunlap@Sun.COM static int 9697978SPeter.Dunlap@Sun.COM idm_itextbuf_add_list_of_values(nvpair_t *nvp, 9707978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx, idm_textbuf_t *itb) 9717978SPeter.Dunlap@Sun.COM { 9727978SPeter.Dunlap@Sun.COM char *key_name; 9737978SPeter.Dunlap@Sun.COM nvpair_t *vchoice = NULL; 9747978SPeter.Dunlap@Sun.COM char *vchoice_string = NULL; 9757978SPeter.Dunlap@Sun.COM int rc; 9767978SPeter.Dunlap@Sun.COM 9777978SPeter.Dunlap@Sun.COM /* Start with the key name */ 9787978SPeter.Dunlap@Sun.COM key_name = nvpair_name(nvp); 9797978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, key_name); 9807978SPeter.Dunlap@Sun.COM 9817978SPeter.Dunlap@Sun.COM /* Add separator */ 9827978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '='); 9837978SPeter.Dunlap@Sun.COM 9847978SPeter.Dunlap@Sun.COM /* Add value choices */ 9857978SPeter.Dunlap@Sun.COM vchoice = idm_get_next_listvalue(nvp, NULL); 9867978SPeter.Dunlap@Sun.COM while (vchoice != NULL) { 9877978SPeter.Dunlap@Sun.COM rc = nvpair_value_string(vchoice, &vchoice_string); 9887978SPeter.Dunlap@Sun.COM ASSERT(rc == 0); 9897978SPeter.Dunlap@Sun.COM textbuf_strcpy(itb, vchoice_string); 9907978SPeter.Dunlap@Sun.COM vchoice = idm_get_next_listvalue(nvp, vchoice); 9917978SPeter.Dunlap@Sun.COM if (vchoice != NULL) { 9927978SPeter.Dunlap@Sun.COM /* Add ',' between choices */ 9937978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, ','); 9947978SPeter.Dunlap@Sun.COM } 9957978SPeter.Dunlap@Sun.COM } 9967978SPeter.Dunlap@Sun.COM 9977978SPeter.Dunlap@Sun.COM /* Add trailing 0x00 */ 9987978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(itb); 9997978SPeter.Dunlap@Sun.COM 10007978SPeter.Dunlap@Sun.COM return (0); 10017978SPeter.Dunlap@Sun.COM } 10027978SPeter.Dunlap@Sun.COM 10037978SPeter.Dunlap@Sun.COM 10047978SPeter.Dunlap@Sun.COM static void 10057978SPeter.Dunlap@Sun.COM textbuf_makeroom(idm_textbuf_t *itb, int size) 10067978SPeter.Dunlap@Sun.COM { 10077978SPeter.Dunlap@Sun.COM char *new_mem; 10087978SPeter.Dunlap@Sun.COM int new_mem_len; 10097978SPeter.Dunlap@Sun.COM 10107978SPeter.Dunlap@Sun.COM if (itb->itb_mem == NULL) { 10117978SPeter.Dunlap@Sun.COM itb->itb_mem_len = MAX(TEXTBUF_CHUNKSIZE, size); 10127978SPeter.Dunlap@Sun.COM itb->itb_mem = kmem_alloc(itb->itb_mem_len, KM_SLEEP); 10137978SPeter.Dunlap@Sun.COM } else if ((itb->itb_offset + size) > itb->itb_mem_len) { 10147978SPeter.Dunlap@Sun.COM new_mem_len = itb->itb_mem_len + MAX(TEXTBUF_CHUNKSIZE, size); 10157978SPeter.Dunlap@Sun.COM new_mem = kmem_alloc(new_mem_len, KM_SLEEP); 10167978SPeter.Dunlap@Sun.COM bcopy(itb->itb_mem, new_mem, itb->itb_mem_len); 10177978SPeter.Dunlap@Sun.COM kmem_free(itb->itb_mem, itb->itb_mem_len); 10187978SPeter.Dunlap@Sun.COM itb->itb_mem = new_mem; 10197978SPeter.Dunlap@Sun.COM itb->itb_mem_len = new_mem_len; 10207978SPeter.Dunlap@Sun.COM } 10217978SPeter.Dunlap@Sun.COM } 10227978SPeter.Dunlap@Sun.COM 10237978SPeter.Dunlap@Sun.COM static void 10247978SPeter.Dunlap@Sun.COM textbuf_memcpy(idm_textbuf_t *itb, void *mem, int mem_len) 10257978SPeter.Dunlap@Sun.COM { 10267978SPeter.Dunlap@Sun.COM textbuf_makeroom(itb, mem_len); 10277978SPeter.Dunlap@Sun.COM (void) memcpy(itb->itb_mem + itb->itb_offset, mem, mem_len); 10287978SPeter.Dunlap@Sun.COM itb->itb_offset += mem_len; 10297978SPeter.Dunlap@Sun.COM } 10307978SPeter.Dunlap@Sun.COM 10317978SPeter.Dunlap@Sun.COM static void 10327978SPeter.Dunlap@Sun.COM textbuf_strcpy(idm_textbuf_t *itb, char *str) 10337978SPeter.Dunlap@Sun.COM { 10347978SPeter.Dunlap@Sun.COM textbuf_memcpy(itb, str, strlen(str)); 10357978SPeter.Dunlap@Sun.COM } 10367978SPeter.Dunlap@Sun.COM 10377978SPeter.Dunlap@Sun.COM static void 10387978SPeter.Dunlap@Sun.COM textbuf_append_char(idm_textbuf_t *itb, char c) 10397978SPeter.Dunlap@Sun.COM { 10407978SPeter.Dunlap@Sun.COM textbuf_makeroom(itb, sizeof (char)); 10417978SPeter.Dunlap@Sun.COM *(itb->itb_mem + itb->itb_offset) = c; 10427978SPeter.Dunlap@Sun.COM itb->itb_offset++; 10437978SPeter.Dunlap@Sun.COM } 10447978SPeter.Dunlap@Sun.COM 10457978SPeter.Dunlap@Sun.COM static void 10467978SPeter.Dunlap@Sun.COM textbuf_terminate_kvpair(idm_textbuf_t *itb) 10477978SPeter.Dunlap@Sun.COM { 10487978SPeter.Dunlap@Sun.COM textbuf_append_char(itb, '\0'); 10497978SPeter.Dunlap@Sun.COM } 10507978SPeter.Dunlap@Sun.COM 10517978SPeter.Dunlap@Sun.COM static int 10527978SPeter.Dunlap@Sun.COM idm_ascii_to_hex(char *enc_hex_byte, uint8_t *bin_val) 10537978SPeter.Dunlap@Sun.COM { 10547978SPeter.Dunlap@Sun.COM uint8_t nibble1, nibble2; 10557978SPeter.Dunlap@Sun.COM char enc_char = *enc_hex_byte; 10567978SPeter.Dunlap@Sun.COM 10577978SPeter.Dunlap@Sun.COM if (enc_char >= '0' && enc_char <= '9') { 10587978SPeter.Dunlap@Sun.COM nibble1 = (enc_char - '0'); 10597978SPeter.Dunlap@Sun.COM } else if (enc_char >= 'A' && enc_char <= 'F') { 10607978SPeter.Dunlap@Sun.COM nibble1 = (0xA + (enc_char - 'A')); 10617978SPeter.Dunlap@Sun.COM } else if (enc_char >= 'a' && enc_char <= 'f') { 10627978SPeter.Dunlap@Sun.COM nibble1 = (0xA + (enc_char - 'a')); 10637978SPeter.Dunlap@Sun.COM } else { 10647978SPeter.Dunlap@Sun.COM return (EINVAL); 10657978SPeter.Dunlap@Sun.COM } 10667978SPeter.Dunlap@Sun.COM 10677978SPeter.Dunlap@Sun.COM enc_hex_byte++; 10687978SPeter.Dunlap@Sun.COM enc_char = *enc_hex_byte; 10697978SPeter.Dunlap@Sun.COM 10707978SPeter.Dunlap@Sun.COM if (enc_char >= '0' && enc_char <= '9') { 10717978SPeter.Dunlap@Sun.COM nibble2 = (enc_char - '0'); 10727978SPeter.Dunlap@Sun.COM } else if (enc_char >= 'A' && enc_char <= 'F') { 10737978SPeter.Dunlap@Sun.COM nibble2 = (0xA + (enc_char - 'A')); 10747978SPeter.Dunlap@Sun.COM } else if (enc_char >= 'a' && enc_char <= 'f') { 10757978SPeter.Dunlap@Sun.COM nibble2 = (0xA + (enc_char - 'a')); 10767978SPeter.Dunlap@Sun.COM } else { 10777978SPeter.Dunlap@Sun.COM return (EINVAL); 10787978SPeter.Dunlap@Sun.COM } 10797978SPeter.Dunlap@Sun.COM 10807978SPeter.Dunlap@Sun.COM *bin_val = (nibble1 << 4) | nibble2; 10817978SPeter.Dunlap@Sun.COM 10827978SPeter.Dunlap@Sun.COM return (0); 10837978SPeter.Dunlap@Sun.COM } 10847978SPeter.Dunlap@Sun.COM 10857978SPeter.Dunlap@Sun.COM 10867978SPeter.Dunlap@Sun.COM static int idm_base16_str_to_binary(char *hstr, int hstr_len, 10877978SPeter.Dunlap@Sun.COM uint8_t *binary_array, int binary_length) 10887978SPeter.Dunlap@Sun.COM { 10897978SPeter.Dunlap@Sun.COM char tmpstr[2]; 10907978SPeter.Dunlap@Sun.COM uchar_t *binary_scan; 10917978SPeter.Dunlap@Sun.COM 10927978SPeter.Dunlap@Sun.COM binary_scan = binary_array; 10937978SPeter.Dunlap@Sun.COM 10947978SPeter.Dunlap@Sun.COM /* 10957978SPeter.Dunlap@Sun.COM * If the length of the encoded ascii hex value is a multiple 10967978SPeter.Dunlap@Sun.COM * of two then every two ascii characters correspond to a hex 10977978SPeter.Dunlap@Sun.COM * byte. If the length of the value is not a multiple of two 10987978SPeter.Dunlap@Sun.COM * then the first character is the first hex byte and then for 10997978SPeter.Dunlap@Sun.COM * the remaining of the string every two ascii characters 11007978SPeter.Dunlap@Sun.COM * correspond to a hex byte 11017978SPeter.Dunlap@Sun.COM */ 11027978SPeter.Dunlap@Sun.COM if ((hstr_len % 2) != 0) { 11037978SPeter.Dunlap@Sun.COM 11047978SPeter.Dunlap@Sun.COM tmpstr[0] = '0'; 11057978SPeter.Dunlap@Sun.COM tmpstr[1] = *hstr; 11067978SPeter.Dunlap@Sun.COM 11077978SPeter.Dunlap@Sun.COM if (idm_ascii_to_hex(tmpstr, binary_scan) != 0) { 11087978SPeter.Dunlap@Sun.COM return (EINVAL); 11097978SPeter.Dunlap@Sun.COM } 11107978SPeter.Dunlap@Sun.COM 11117978SPeter.Dunlap@Sun.COM hstr++; 11127978SPeter.Dunlap@Sun.COM binary_scan++; 11137978SPeter.Dunlap@Sun.COM } 11147978SPeter.Dunlap@Sun.COM 11157978SPeter.Dunlap@Sun.COM while (binary_scan != binary_array + binary_length) { 11167978SPeter.Dunlap@Sun.COM if (idm_ascii_to_hex(hstr, binary_scan) != 0) { 11177978SPeter.Dunlap@Sun.COM return (EINVAL); 11187978SPeter.Dunlap@Sun.COM } 11197978SPeter.Dunlap@Sun.COM 11207978SPeter.Dunlap@Sun.COM hstr += 2; 11217978SPeter.Dunlap@Sun.COM binary_scan++; 11227978SPeter.Dunlap@Sun.COM } 11237978SPeter.Dunlap@Sun.COM 11247978SPeter.Dunlap@Sun.COM return (0); 11257978SPeter.Dunlap@Sun.COM } 11267978SPeter.Dunlap@Sun.COM 11277978SPeter.Dunlap@Sun.COM static size_t 11287978SPeter.Dunlap@Sun.COM idm_strnlen(const char *str, size_t maxlen) 11297978SPeter.Dunlap@Sun.COM { 11307978SPeter.Dunlap@Sun.COM const char *ptr; 11317978SPeter.Dunlap@Sun.COM 11327978SPeter.Dunlap@Sun.COM ptr = memchr(str, 0, maxlen); 11337978SPeter.Dunlap@Sun.COM if (ptr == NULL) 11347978SPeter.Dunlap@Sun.COM return (maxlen); 11357978SPeter.Dunlap@Sun.COM 11367978SPeter.Dunlap@Sun.COM return ((uintptr_t)ptr - (uintptr_t)str); 11377978SPeter.Dunlap@Sun.COM } 11387978SPeter.Dunlap@Sun.COM 11397978SPeter.Dunlap@Sun.COM 11407978SPeter.Dunlap@Sun.COM size_t 11417978SPeter.Dunlap@Sun.COM idm_strcspn(const char *string, const char *charset) 11427978SPeter.Dunlap@Sun.COM { 11437978SPeter.Dunlap@Sun.COM const char *p, *q; 11447978SPeter.Dunlap@Sun.COM 11457978SPeter.Dunlap@Sun.COM for (q = string; *q != '\0'; ++q) { 11467978SPeter.Dunlap@Sun.COM for (p = charset; *p != '\0' && *p != *q; ) 11477978SPeter.Dunlap@Sun.COM p++; 11487978SPeter.Dunlap@Sun.COM if (*p != '\0') { 11497978SPeter.Dunlap@Sun.COM break; 11507978SPeter.Dunlap@Sun.COM } 11517978SPeter.Dunlap@Sun.COM } 11527978SPeter.Dunlap@Sun.COM return ((uintptr_t)q - (uintptr_t)string); 11537978SPeter.Dunlap@Sun.COM } 11547978SPeter.Dunlap@Sun.COM 11557978SPeter.Dunlap@Sun.COM /* 11567978SPeter.Dunlap@Sun.COM * We allow a list of choices to be represented as a single nvpair 11577978SPeter.Dunlap@Sun.COM * (list with one value choice), or as an nvlist with a single nvpair 11587978SPeter.Dunlap@Sun.COM * (also a list with on value choice), or as an nvlist with multiple 11597978SPeter.Dunlap@Sun.COM * nvpairs (a list with multiple value choices). This function implements 11607978SPeter.Dunlap@Sun.COM * the "get next" functionality regardless of the choice list structure. 11617978SPeter.Dunlap@Sun.COM * 11627978SPeter.Dunlap@Sun.COM * nvpair_t's that contain choices are always strings. 11637978SPeter.Dunlap@Sun.COM */ 11647978SPeter.Dunlap@Sun.COM nvpair_t * 11657978SPeter.Dunlap@Sun.COM idm_get_next_listvalue(nvpair_t *value_list, nvpair_t *curr_nvp) 11667978SPeter.Dunlap@Sun.COM { 11677978SPeter.Dunlap@Sun.COM nvpair_t *result; 11687978SPeter.Dunlap@Sun.COM nvlist_t *nvl; 11697978SPeter.Dunlap@Sun.COM int nvrc; 11707978SPeter.Dunlap@Sun.COM data_type_t nvp_type; 11717978SPeter.Dunlap@Sun.COM 11727978SPeter.Dunlap@Sun.COM nvp_type = nvpair_type(value_list); 11737978SPeter.Dunlap@Sun.COM 11747978SPeter.Dunlap@Sun.COM switch (nvp_type) { 11757978SPeter.Dunlap@Sun.COM case DATA_TYPE_NVLIST: 11767978SPeter.Dunlap@Sun.COM nvrc = nvpair_value_nvlist(value_list, &nvl); 11777978SPeter.Dunlap@Sun.COM ASSERT(nvrc == 0); 11787978SPeter.Dunlap@Sun.COM result = nvlist_next_nvpair(nvl, curr_nvp); 11797978SPeter.Dunlap@Sun.COM break; 11807978SPeter.Dunlap@Sun.COM case DATA_TYPE_STRING: 11817978SPeter.Dunlap@Sun.COM /* Single choice */ 11827978SPeter.Dunlap@Sun.COM if (curr_nvp == NULL) { 11837978SPeter.Dunlap@Sun.COM result = value_list; 11847978SPeter.Dunlap@Sun.COM } else { 11857978SPeter.Dunlap@Sun.COM result = NULL; 11867978SPeter.Dunlap@Sun.COM } 11877978SPeter.Dunlap@Sun.COM break; 11887978SPeter.Dunlap@Sun.COM default: 11897978SPeter.Dunlap@Sun.COM ASSERT(0); /* Malformed choice list */ 11907978SPeter.Dunlap@Sun.COM result = NULL; 11917978SPeter.Dunlap@Sun.COM break; 11927978SPeter.Dunlap@Sun.COM } 11937978SPeter.Dunlap@Sun.COM 11947978SPeter.Dunlap@Sun.COM return (result); 11957978SPeter.Dunlap@Sun.COM } 11967978SPeter.Dunlap@Sun.COM 11977978SPeter.Dunlap@Sun.COM kv_status_t 11987978SPeter.Dunlap@Sun.COM idm_nvstat_to_kvstat(int nvrc) 11997978SPeter.Dunlap@Sun.COM { 12007978SPeter.Dunlap@Sun.COM kv_status_t result; 12017978SPeter.Dunlap@Sun.COM switch (nvrc) { 12027978SPeter.Dunlap@Sun.COM case 0: 12037978SPeter.Dunlap@Sun.COM result = KV_HANDLED; 12047978SPeter.Dunlap@Sun.COM break; 12057978SPeter.Dunlap@Sun.COM case ENOMEM: 12067978SPeter.Dunlap@Sun.COM result = KV_NO_RESOURCES; 12077978SPeter.Dunlap@Sun.COM break; 12087978SPeter.Dunlap@Sun.COM case EINVAL: 12097978SPeter.Dunlap@Sun.COM result = KV_VALUE_ERROR; 12107978SPeter.Dunlap@Sun.COM break; 12117978SPeter.Dunlap@Sun.COM case EFAULT: 12127978SPeter.Dunlap@Sun.COM case ENOTSUP: 12137978SPeter.Dunlap@Sun.COM default: 12147978SPeter.Dunlap@Sun.COM result = KV_INTERNAL_ERROR; 12157978SPeter.Dunlap@Sun.COM break; 12167978SPeter.Dunlap@Sun.COM } 12177978SPeter.Dunlap@Sun.COM 12187978SPeter.Dunlap@Sun.COM return (result); 12197978SPeter.Dunlap@Sun.COM } 12207978SPeter.Dunlap@Sun.COM 12217978SPeter.Dunlap@Sun.COM void 12227978SPeter.Dunlap@Sun.COM idm_kvstat_to_error(kv_status_t kvrc, uint8_t *class, uint8_t *detail) 12237978SPeter.Dunlap@Sun.COM { 12247978SPeter.Dunlap@Sun.COM switch (kvrc) { 12257978SPeter.Dunlap@Sun.COM case KV_HANDLED: 12267978SPeter.Dunlap@Sun.COM case KV_HANDLED_NO_TRANSIT: 12277978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_SUCCESS; 12287978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_ACCEPT; 12297978SPeter.Dunlap@Sun.COM break; 12307978SPeter.Dunlap@Sun.COM case KV_UNHANDLED: 12317978SPeter.Dunlap@Sun.COM case KV_TARGET_ONLY: 12327978SPeter.Dunlap@Sun.COM /* protocol error */ 12337978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 12347978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_INVALID_REQUEST; 12357978SPeter.Dunlap@Sun.COM break; 12367978SPeter.Dunlap@Sun.COM case KV_VALUE_ERROR: 12377978SPeter.Dunlap@Sun.COM /* invalid value */ 12387978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 12397978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_INIT_ERR; 12407978SPeter.Dunlap@Sun.COM break; 12417978SPeter.Dunlap@Sun.COM case KV_NO_RESOURCES: 12427978SPeter.Dunlap@Sun.COM /* no memory */ 12437978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_TARGET_ERR; 12447978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_NO_RESOURCES; 12457978SPeter.Dunlap@Sun.COM break; 12467978SPeter.Dunlap@Sun.COM case KV_MISSING_FIELDS: 12477978SPeter.Dunlap@Sun.COM /* key/value pair(s) missing */ 12487978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 12497978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_MISSING_FIELDS; 12507978SPeter.Dunlap@Sun.COM break; 12517978SPeter.Dunlap@Sun.COM case KV_AUTH_FAILED: 12527978SPeter.Dunlap@Sun.COM /* authentication failed */ 12537978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_INITIATOR_ERR; 12547978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_AUTH_FAILED; 12557978SPeter.Dunlap@Sun.COM break; 12567978SPeter.Dunlap@Sun.COM default: 12577978SPeter.Dunlap@Sun.COM /* target error */ 12587978SPeter.Dunlap@Sun.COM *class = ISCSI_STATUS_CLASS_TARGET_ERR; 12597978SPeter.Dunlap@Sun.COM *detail = ISCSI_LOGIN_STATUS_TARGET_ERROR; 12607978SPeter.Dunlap@Sun.COM break; 12617978SPeter.Dunlap@Sun.COM } 12627978SPeter.Dunlap@Sun.COM } 12637978SPeter.Dunlap@Sun.COM 12647978SPeter.Dunlap@Sun.COM int 12657978SPeter.Dunlap@Sun.COM idm_nvlist_add_keyvalue(nvlist_t *nvl, 12667978SPeter.Dunlap@Sun.COM char *key, int keylen, char *value) 12677978SPeter.Dunlap@Sun.COM { 12687978SPeter.Dunlap@Sun.COM const idm_kv_xlate_t *ikvx; 12697978SPeter.Dunlap@Sun.COM 12707978SPeter.Dunlap@Sun.COM ikvx = idm_lookup_kv_xlate(key, keylen); 12717978SPeter.Dunlap@Sun.COM 12727978SPeter.Dunlap@Sun.COM if (ikvx->ik_key_id == KI_MAX_KEY) { 12738435SJames.Moore@Sun.COM char *nkey; 12748435SJames.Moore@Sun.COM int rc; 12758435SJames.Moore@Sun.COM size_t len; 12768435SJames.Moore@Sun.COM 12778435SJames.Moore@Sun.COM /* 12788435SJames.Moore@Sun.COM * key is not a NULL terminated string, so create one 12798435SJames.Moore@Sun.COM */ 12808435SJames.Moore@Sun.COM len = (size_t)(keylen+1); 12818435SJames.Moore@Sun.COM nkey = kmem_zalloc(len, KM_SLEEP); 12828435SJames.Moore@Sun.COM (void) strncpy(nkey, key, len-1); 12838435SJames.Moore@Sun.COM rc = nvlist_add_string(nvl, nkey, value); 12848435SJames.Moore@Sun.COM kmem_free(nkey, len); 12858435SJames.Moore@Sun.COM return (rc); 12867978SPeter.Dunlap@Sun.COM } 12877978SPeter.Dunlap@Sun.COM 12887978SPeter.Dunlap@Sun.COM return (idm_nvlist_add_kv(nvl, ikvx, value)); 12897978SPeter.Dunlap@Sun.COM } 12907978SPeter.Dunlap@Sun.COM 12917978SPeter.Dunlap@Sun.COM int 12927978SPeter.Dunlap@Sun.COM idm_nvlist_add_id(nvlist_t *nvl, iscsikey_id_t kv_id, char *value) 12937978SPeter.Dunlap@Sun.COM { 12947978SPeter.Dunlap@Sun.COM int i; 12957978SPeter.Dunlap@Sun.COM for (i = 0; i < KI_MAX_KEY; i++) { 12967978SPeter.Dunlap@Sun.COM if (idm_kvpair_xlate[i].ik_key_id == kv_id) { 12977978SPeter.Dunlap@Sun.COM return 12987978SPeter.Dunlap@Sun.COM (idm_nvlist_add_kv(nvl, 12997978SPeter.Dunlap@Sun.COM &idm_kvpair_xlate[i], value)); 13007978SPeter.Dunlap@Sun.COM } 13017978SPeter.Dunlap@Sun.COM } 13027978SPeter.Dunlap@Sun.COM return (EFAULT); 13037978SPeter.Dunlap@Sun.COM } 13047978SPeter.Dunlap@Sun.COM 13057978SPeter.Dunlap@Sun.COM char * 13067978SPeter.Dunlap@Sun.COM idm_id_to_name(iscsikey_id_t kv_id) 13077978SPeter.Dunlap@Sun.COM { 13087978SPeter.Dunlap@Sun.COM int i; 13097978SPeter.Dunlap@Sun.COM for (i = 0; i < KI_MAX_KEY; i++) { 13107978SPeter.Dunlap@Sun.COM if (idm_kvpair_xlate[i].ik_key_id == kv_id) { 13117978SPeter.Dunlap@Sun.COM return (idm_kvpair_xlate[i].ik_key_name); 13127978SPeter.Dunlap@Sun.COM } 13137978SPeter.Dunlap@Sun.COM } 13147978SPeter.Dunlap@Sun.COM return (NULL); 13157978SPeter.Dunlap@Sun.COM } 13167978SPeter.Dunlap@Sun.COM 13177978SPeter.Dunlap@Sun.COM /* 13187978SPeter.Dunlap@Sun.COM * return the value in a buffer that must be freed by the caller 13197978SPeter.Dunlap@Sun.COM */ 13207978SPeter.Dunlap@Sun.COM char * 13217978SPeter.Dunlap@Sun.COM idm_nvpair_value_to_textbuf(nvpair_t *nvp) 13227978SPeter.Dunlap@Sun.COM { 13237978SPeter.Dunlap@Sun.COM int rv, len; 13247978SPeter.Dunlap@Sun.COM idm_textbuf_t itb; 13257978SPeter.Dunlap@Sun.COM char *str; 13267978SPeter.Dunlap@Sun.COM 13277978SPeter.Dunlap@Sun.COM bzero(&itb, sizeof (itb)); 13287978SPeter.Dunlap@Sun.COM rv = idm_itextbuf_add_nvpair(nvp, &itb); 13297978SPeter.Dunlap@Sun.COM if (rv != 0) 13307978SPeter.Dunlap@Sun.COM return (NULL); 13317978SPeter.Dunlap@Sun.COM str = kmem_alloc(itb.itb_mem_len, KM_SLEEP); 13327978SPeter.Dunlap@Sun.COM len = idm_strcspn(itb.itb_mem, "="); 13337978SPeter.Dunlap@Sun.COM if (len > strlen(itb.itb_mem)) { 13347978SPeter.Dunlap@Sun.COM kmem_free(itb.itb_mem, itb.itb_mem_len); 13357978SPeter.Dunlap@Sun.COM return (NULL); 13367978SPeter.Dunlap@Sun.COM } 13377978SPeter.Dunlap@Sun.COM (void) strcpy(str, &itb.itb_mem[len+1]); 13387978SPeter.Dunlap@Sun.COM /* free the allocation done in idm_textbuf_add_nvpair */ 13397978SPeter.Dunlap@Sun.COM kmem_free(itb.itb_mem, itb.itb_mem_len); 13407978SPeter.Dunlap@Sun.COM return (str); 13417978SPeter.Dunlap@Sun.COM } 13427978SPeter.Dunlap@Sun.COM 13437978SPeter.Dunlap@Sun.COM /* 13447978SPeter.Dunlap@Sun.COM * build an iscsi text buffer - the memory gets freed in 13457978SPeter.Dunlap@Sun.COM * idm_itextbuf_free 13467978SPeter.Dunlap@Sun.COM */ 13477978SPeter.Dunlap@Sun.COM void * 13487978SPeter.Dunlap@Sun.COM idm_nvlist_to_itextbuf(nvlist_t *nvl) 13497978SPeter.Dunlap@Sun.COM { 13507978SPeter.Dunlap@Sun.COM idm_textbuf_t *itb; 13517978SPeter.Dunlap@Sun.COM char *textbuf; 13527978SPeter.Dunlap@Sun.COM int validlen, textbuflen; 13537978SPeter.Dunlap@Sun.COM 13547978SPeter.Dunlap@Sun.COM if (idm_nvlist_to_textbuf(nvl, &textbuf, &textbuflen, 13557978SPeter.Dunlap@Sun.COM &validlen) != IDM_STATUS_SUCCESS) { 13567978SPeter.Dunlap@Sun.COM return (NULL); 13577978SPeter.Dunlap@Sun.COM } 13587978SPeter.Dunlap@Sun.COM itb = kmem_zalloc(sizeof (idm_textbuf_t), KM_SLEEP); 13597978SPeter.Dunlap@Sun.COM ASSERT(itb != NULL); 13607978SPeter.Dunlap@Sun.COM itb->itb_mem = textbuf; 13617978SPeter.Dunlap@Sun.COM itb->itb_mem_len = textbuflen; 13627978SPeter.Dunlap@Sun.COM itb->itb_offset = validlen; 13637978SPeter.Dunlap@Sun.COM return ((void *)itb); 13647978SPeter.Dunlap@Sun.COM } 13657978SPeter.Dunlap@Sun.COM 13667978SPeter.Dunlap@Sun.COM /* 13677978SPeter.Dunlap@Sun.COM * Update the pdu data up to min of max_xfer_len or data left. 13687978SPeter.Dunlap@Sun.COM * The first call to this routine should send 13697978SPeter.Dunlap@Sun.COM * a NULL bufptr. Subsequent calls send in the buffer returned. 13707978SPeter.Dunlap@Sun.COM * Call this routine until the string returned is NULL 13717978SPeter.Dunlap@Sun.COM */ 13727978SPeter.Dunlap@Sun.COM char * 13737978SPeter.Dunlap@Sun.COM idm_pdu_init_text_data(idm_pdu_t *pdu, void *arg, 13747978SPeter.Dunlap@Sun.COM int max_xfer_len, char *bufptr, int *transit) 13757978SPeter.Dunlap@Sun.COM { 13767978SPeter.Dunlap@Sun.COM char *start_ptr, *end_ptr, *ptr; 13777978SPeter.Dunlap@Sun.COM idm_textbuf_t *itb = arg; 13787978SPeter.Dunlap@Sun.COM iscsi_hdr_t *ihp = pdu->isp_hdr; 13797978SPeter.Dunlap@Sun.COM int send = 0; 13807978SPeter.Dunlap@Sun.COM 13817978SPeter.Dunlap@Sun.COM ASSERT(itb != NULL); 13827978SPeter.Dunlap@Sun.COM ASSERT(pdu != NULL); 13837978SPeter.Dunlap@Sun.COM ASSERT(transit != NULL); 13847978SPeter.Dunlap@Sun.COM if (bufptr == NULL) { 13857978SPeter.Dunlap@Sun.COM /* first call - check the length */ 13867978SPeter.Dunlap@Sun.COM if (itb->itb_offset <= max_xfer_len) { 13877978SPeter.Dunlap@Sun.COM idm_pdu_init_data(pdu, (uint8_t *)itb->itb_mem, 13887978SPeter.Dunlap@Sun.COM itb->itb_offset); 13897978SPeter.Dunlap@Sun.COM ihp->flags &= ~ISCSI_FLAG_TEXT_CONTINUE; 13907978SPeter.Dunlap@Sun.COM *transit = 1; 13917978SPeter.Dunlap@Sun.COM return (NULL); 13927978SPeter.Dunlap@Sun.COM } 13937978SPeter.Dunlap@Sun.COM /* we have more data than will fit in one pdu */ 13947978SPeter.Dunlap@Sun.COM start_ptr = itb->itb_mem; 13957978SPeter.Dunlap@Sun.COM end_ptr = &itb->itb_mem[max_xfer_len - 1]; 13967978SPeter.Dunlap@Sun.COM 13977978SPeter.Dunlap@Sun.COM } else { 13987978SPeter.Dunlap@Sun.COM if ((uintptr_t)&itb->itb_mem[itb->itb_offset] - 13997978SPeter.Dunlap@Sun.COM (uintptr_t)bufptr <= max_xfer_len) { 14007978SPeter.Dunlap@Sun.COM idm_pdu_init_data(pdu, (uint8_t *)bufptr, 14017978SPeter.Dunlap@Sun.COM (uintptr_t)&itb->itb_mem[itb->itb_offset] - 14027978SPeter.Dunlap@Sun.COM (uintptr_t)bufptr); 14037978SPeter.Dunlap@Sun.COM ihp->flags &= ~ISCSI_FLAG_TEXT_CONTINUE; 14047978SPeter.Dunlap@Sun.COM *transit = 1; 14057978SPeter.Dunlap@Sun.COM return (NULL); 14067978SPeter.Dunlap@Sun.COM } 14077978SPeter.Dunlap@Sun.COM /* we have more data then will fit in one pdu */ 14087978SPeter.Dunlap@Sun.COM start_ptr = bufptr; 14097978SPeter.Dunlap@Sun.COM end_ptr = &bufptr[max_xfer_len - 1]; 14107978SPeter.Dunlap@Sun.COM } 14117978SPeter.Dunlap@Sun.COM /* break after key, after =, after the value or after '\0' */ 14127978SPeter.Dunlap@Sun.COM ptr = end_ptr; 14137978SPeter.Dunlap@Sun.COM if (end_ptr + 1 <= &itb->itb_mem[itb->itb_offset]) { 14147978SPeter.Dunlap@Sun.COM /* if next char is an '=' or '\0' send it */ 14157978SPeter.Dunlap@Sun.COM if (*(end_ptr + 1) == '=' || *(end_ptr + 1) == '\0') { 14167978SPeter.Dunlap@Sun.COM send = 1; 14177978SPeter.Dunlap@Sun.COM } 14187978SPeter.Dunlap@Sun.COM } 14197978SPeter.Dunlap@Sun.COM if (!send) { 14207978SPeter.Dunlap@Sun.COM while (*ptr != '\0' && *ptr != '=' && ptr != start_ptr) { 14217978SPeter.Dunlap@Sun.COM ptr--; 14227978SPeter.Dunlap@Sun.COM } 14237978SPeter.Dunlap@Sun.COM } 14247978SPeter.Dunlap@Sun.COM idm_pdu_init_data(pdu, (uint8_t *)start_ptr, 14257978SPeter.Dunlap@Sun.COM ((uintptr_t)ptr - (uintptr_t)start_ptr) + 1); 14267978SPeter.Dunlap@Sun.COM ihp->flags |= ISCSI_FLAG_TEXT_CONTINUE; 14277978SPeter.Dunlap@Sun.COM *transit = 0; 14287978SPeter.Dunlap@Sun.COM return (++ptr); 14297978SPeter.Dunlap@Sun.COM } 14307978SPeter.Dunlap@Sun.COM 14317978SPeter.Dunlap@Sun.COM void 14327978SPeter.Dunlap@Sun.COM idm_itextbuf_free(void *arg) 14337978SPeter.Dunlap@Sun.COM { 14347978SPeter.Dunlap@Sun.COM idm_textbuf_t *itb = arg; 14357978SPeter.Dunlap@Sun.COM ASSERT(itb != NULL); 14367978SPeter.Dunlap@Sun.COM kmem_free(itb->itb_mem, itb->itb_mem_len); 14377978SPeter.Dunlap@Sun.COM kmem_free(itb, sizeof (idm_textbuf_t)); 14387978SPeter.Dunlap@Sun.COM } 14397978SPeter.Dunlap@Sun.COM 14407978SPeter.Dunlap@Sun.COM /* 14417978SPeter.Dunlap@Sun.COM * Allocate an nvlist and poputlate with key=value from the pdu list. 14427978SPeter.Dunlap@Sun.COM * NOTE: caller must free the list 14437978SPeter.Dunlap@Sun.COM */ 14447978SPeter.Dunlap@Sun.COM idm_status_t 14457978SPeter.Dunlap@Sun.COM idm_pdu_list_to_nvlist(list_t *pdu_list, nvlist_t **nvlist, 14467978SPeter.Dunlap@Sun.COM uint8_t *error_detail) 14477978SPeter.Dunlap@Sun.COM { 14487978SPeter.Dunlap@Sun.COM idm_pdu_t *pdu, *next_pdu; 14497978SPeter.Dunlap@Sun.COM boolean_t split_kv = B_FALSE; 14507978SPeter.Dunlap@Sun.COM char *textbuf, *leftover_textbuf = NULL; 14517978SPeter.Dunlap@Sun.COM int textbuflen, leftover_textbuflen = 0; 14527978SPeter.Dunlap@Sun.COM char *split_kvbuf; 14537978SPeter.Dunlap@Sun.COM int split_kvbuflen, cont_fraglen; 14547978SPeter.Dunlap@Sun.COM iscsi_login_hdr_t *lh; 14557978SPeter.Dunlap@Sun.COM int rc; 14567978SPeter.Dunlap@Sun.COM int ret = IDM_STATUS_SUCCESS; 14577978SPeter.Dunlap@Sun.COM 14587978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_ACCEPT; 14597978SPeter.Dunlap@Sun.COM /* Allocate a new nvlist for request key/value pairs */ 14607978SPeter.Dunlap@Sun.COM rc = nvlist_alloc(nvlist, NV_UNIQUE_NAME, 14617978SPeter.Dunlap@Sun.COM KM_NOSLEEP); 14627978SPeter.Dunlap@Sun.COM if (rc != 0) { 14637978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES; 14647978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 14657978SPeter.Dunlap@Sun.COM goto cleanup; 14667978SPeter.Dunlap@Sun.COM } 14677978SPeter.Dunlap@Sun.COM 14687978SPeter.Dunlap@Sun.COM /* 14697978SPeter.Dunlap@Sun.COM * A login request can be split across multiple PDU's. The state 14707978SPeter.Dunlap@Sun.COM * machine has collected all the PDU's that make up this login request 14717978SPeter.Dunlap@Sun.COM * and assembled them on the "icl_pdu_list" queue. Process each PDU 14727978SPeter.Dunlap@Sun.COM * and convert the text keywords to nvlist form. 14737978SPeter.Dunlap@Sun.COM */ 14747978SPeter.Dunlap@Sun.COM pdu = list_head(pdu_list); 14757978SPeter.Dunlap@Sun.COM while (pdu != NULL) { 14767978SPeter.Dunlap@Sun.COM next_pdu = list_next(pdu_list, pdu); 14777978SPeter.Dunlap@Sun.COM 14787978SPeter.Dunlap@Sun.COM lh = (iscsi_login_hdr_t *)pdu->isp_hdr; 14797978SPeter.Dunlap@Sun.COM 14807978SPeter.Dunlap@Sun.COM textbuf = (char *)pdu->isp_data; 14817978SPeter.Dunlap@Sun.COM textbuflen = pdu->isp_datalen; 14827978SPeter.Dunlap@Sun.COM if (textbuflen == 0) { 14837978SPeter.Dunlap@Sun.COM /* This shouldn't really happen but it could.. */ 14847978SPeter.Dunlap@Sun.COM list_remove(pdu_list, pdu); 14857978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 14867978SPeter.Dunlap@Sun.COM pdu = next_pdu; 14877978SPeter.Dunlap@Sun.COM continue; 14887978SPeter.Dunlap@Sun.COM } 14897978SPeter.Dunlap@Sun.COM 14907978SPeter.Dunlap@Sun.COM /* 14917978SPeter.Dunlap@Sun.COM * If we encountered a split key-value pair on the last 14927978SPeter.Dunlap@Sun.COM * PDU then handle it now by grabbing the remainder of the 14937978SPeter.Dunlap@Sun.COM * key-value pair from the next PDU and splicing them 14947978SPeter.Dunlap@Sun.COM * together. Obviously on the first PDU this will never 14957978SPeter.Dunlap@Sun.COM * happen. 14967978SPeter.Dunlap@Sun.COM */ 14977978SPeter.Dunlap@Sun.COM if (split_kv) { 14987978SPeter.Dunlap@Sun.COM cont_fraglen = idm_textbuf_to_firstfraglen(textbuf, 14997978SPeter.Dunlap@Sun.COM textbuflen); 15007978SPeter.Dunlap@Sun.COM if (cont_fraglen == pdu->isp_datalen) { 15017978SPeter.Dunlap@Sun.COM /* 15027978SPeter.Dunlap@Sun.COM * This key-value pair spans more than two 15037978SPeter.Dunlap@Sun.COM * PDU's. We don't handle this. 15047978SPeter.Dunlap@Sun.COM */ 15057978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR; 15067978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 15077978SPeter.Dunlap@Sun.COM goto cleanup; 15087978SPeter.Dunlap@Sun.COM } 15097978SPeter.Dunlap@Sun.COM 15107978SPeter.Dunlap@Sun.COM split_kvbuflen = leftover_textbuflen + cont_fraglen; 15117978SPeter.Dunlap@Sun.COM split_kvbuf = kmem_alloc(split_kvbuflen, KM_NOSLEEP); 15127978SPeter.Dunlap@Sun.COM if (split_kvbuf == NULL) { 15137978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_NO_RESOURCES; 15147978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 15157978SPeter.Dunlap@Sun.COM goto cleanup; 15167978SPeter.Dunlap@Sun.COM } 15177978SPeter.Dunlap@Sun.COM 15187978SPeter.Dunlap@Sun.COM bcopy(leftover_textbuf, split_kvbuf, 15197978SPeter.Dunlap@Sun.COM leftover_textbuflen); 15207978SPeter.Dunlap@Sun.COM bcopy(textbuf, 15217978SPeter.Dunlap@Sun.COM (uint8_t *)split_kvbuf + leftover_textbuflen, 15227978SPeter.Dunlap@Sun.COM cont_fraglen); 15237978SPeter.Dunlap@Sun.COM 15247978SPeter.Dunlap@Sun.COM 15257978SPeter.Dunlap@Sun.COM if (idm_textbuf_to_nvlist(*nvlist, 15267978SPeter.Dunlap@Sun.COM &split_kvbuf, &split_kvbuflen) != 0) { 15277978SPeter.Dunlap@Sun.COM /* 15287978SPeter.Dunlap@Sun.COM * Need to handle E2BIG case, indicating that 15297978SPeter.Dunlap@Sun.COM * a key-value pair is split across multiple 15307978SPeter.Dunlap@Sun.COM * PDU's. 15317978SPeter.Dunlap@Sun.COM */ 15327978SPeter.Dunlap@Sun.COM kmem_free(split_kvbuf, split_kvbuflen); 15337978SPeter.Dunlap@Sun.COM 15347978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR; 15357978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 15367978SPeter.Dunlap@Sun.COM goto cleanup; 15377978SPeter.Dunlap@Sun.COM } 15387978SPeter.Dunlap@Sun.COM 15397978SPeter.Dunlap@Sun.COM ASSERT(split_kvbuflen != NULL); 15407978SPeter.Dunlap@Sun.COM kmem_free(split_kvbuf, split_kvbuflen); 15417978SPeter.Dunlap@Sun.COM 15427978SPeter.Dunlap@Sun.COM /* Now handle the remainder of the PDU as normal */ 15437978SPeter.Dunlap@Sun.COM textbuf += (cont_fraglen + 1); 15447978SPeter.Dunlap@Sun.COM textbuflen -= (cont_fraglen + 1); 15457978SPeter.Dunlap@Sun.COM } 15467978SPeter.Dunlap@Sun.COM 15477978SPeter.Dunlap@Sun.COM /* 15487978SPeter.Dunlap@Sun.COM * Convert each key-value pair in the text buffer to nvlist 15497978SPeter.Dunlap@Sun.COM * format. If the list has already been created the nvpair 15507978SPeter.Dunlap@Sun.COM * elements will be added on to the existing list. Otherwise 15517978SPeter.Dunlap@Sun.COM * a new nvlist will be created. 15527978SPeter.Dunlap@Sun.COM */ 15537978SPeter.Dunlap@Sun.COM if (idm_textbuf_to_nvlist(*nvlist, 15547978SPeter.Dunlap@Sun.COM &textbuf, &textbuflen) != 0) { 15557978SPeter.Dunlap@Sun.COM 15567978SPeter.Dunlap@Sun.COM *error_detail = ISCSI_LOGIN_STATUS_TARGET_ERROR; 15577978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 15587978SPeter.Dunlap@Sun.COM goto cleanup; 15597978SPeter.Dunlap@Sun.COM } 15607978SPeter.Dunlap@Sun.COM 15617978SPeter.Dunlap@Sun.COM ASSERT( 15627978SPeter.Dunlap@Sun.COM ((lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) && 15637978SPeter.Dunlap@Sun.COM (next_pdu != NULL)) || 15647978SPeter.Dunlap@Sun.COM (!(lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) && 15657978SPeter.Dunlap@Sun.COM (next_pdu == NULL))); 15667978SPeter.Dunlap@Sun.COM 15677978SPeter.Dunlap@Sun.COM if ((lh->flags & ISCSI_FLAG_LOGIN_CONTINUE) & 15687978SPeter.Dunlap@Sun.COM (textbuflen != 0)) { 15697978SPeter.Dunlap@Sun.COM /* 15707978SPeter.Dunlap@Sun.COM * Key-value pair is split over two PDU's. We 15717978SPeter.Dunlap@Sun.COM * assume it willl never be split over more than 15727978SPeter.Dunlap@Sun.COM * two PDU's. 15737978SPeter.Dunlap@Sun.COM */ 15747978SPeter.Dunlap@Sun.COM split_kv = B_TRUE; 15757978SPeter.Dunlap@Sun.COM leftover_textbuf = textbuf; 15767978SPeter.Dunlap@Sun.COM leftover_textbuflen = textbuflen; 15777978SPeter.Dunlap@Sun.COM } else { 15787978SPeter.Dunlap@Sun.COM split_kv = B_FALSE; 15797978SPeter.Dunlap@Sun.COM if (textbuflen != 0) { 15807978SPeter.Dunlap@Sun.COM /* 15817978SPeter.Dunlap@Sun.COM * Incomplete keyword but no additional 15827978SPeter.Dunlap@Sun.COM * PDU's. This is a malformed login 15837978SPeter.Dunlap@Sun.COM * request. 15847978SPeter.Dunlap@Sun.COM */ 15857978SPeter.Dunlap@Sun.COM *error_detail = 15867978SPeter.Dunlap@Sun.COM ISCSI_LOGIN_STATUS_INVALID_REQUEST; 15877978SPeter.Dunlap@Sun.COM ret = IDM_STATUS_FAIL; 15887978SPeter.Dunlap@Sun.COM goto cleanup; 15897978SPeter.Dunlap@Sun.COM } 15907978SPeter.Dunlap@Sun.COM } 15917978SPeter.Dunlap@Sun.COM 15927978SPeter.Dunlap@Sun.COM list_remove(pdu_list, pdu); 15937978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 15947978SPeter.Dunlap@Sun.COM pdu = next_pdu; 15957978SPeter.Dunlap@Sun.COM } 15967978SPeter.Dunlap@Sun.COM 15977978SPeter.Dunlap@Sun.COM cleanup: 15987978SPeter.Dunlap@Sun.COM 15997978SPeter.Dunlap@Sun.COM /* 16007978SPeter.Dunlap@Sun.COM * Free any remaining PDUs on the list. This will only 16017978SPeter.Dunlap@Sun.COM * happen if there were errors encountered during 16027978SPeter.Dunlap@Sun.COM * processing of the textbuf. 16037978SPeter.Dunlap@Sun.COM */ 16047978SPeter.Dunlap@Sun.COM pdu = list_head(pdu_list); 16057978SPeter.Dunlap@Sun.COM while (pdu != NULL) { 16067978SPeter.Dunlap@Sun.COM next_pdu = list_next(pdu_list, pdu); 16077978SPeter.Dunlap@Sun.COM list_remove(pdu_list, pdu); 16087978SPeter.Dunlap@Sun.COM idm_pdu_complete(pdu, IDM_STATUS_SUCCESS); 16097978SPeter.Dunlap@Sun.COM pdu = next_pdu; 16107978SPeter.Dunlap@Sun.COM } 16117978SPeter.Dunlap@Sun.COM 16127978SPeter.Dunlap@Sun.COM /* 16137978SPeter.Dunlap@Sun.COM * If there were no errors, we have a complete nvlist representing 16147978SPeter.Dunlap@Sun.COM * all the iSCSI key-value pairs in the login request PDU's 16157978SPeter.Dunlap@Sun.COM * that make up this request. 16167978SPeter.Dunlap@Sun.COM */ 16177978SPeter.Dunlap@Sun.COM return (ret); 16187978SPeter.Dunlap@Sun.COM } 1619