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