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