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