1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. 5 * Copyright (c) Intel Corporation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 37 #include "spdk/string.h" 38 #include "iscsi/iscsi.h" 39 #include "iscsi/param.h" 40 #include "iscsi/conn.h" 41 #include "spdk/string.h" 42 43 #include "spdk/log.h" 44 45 #define MAX_TMPBUF 1024 46 47 /* whose value may be bigger than 255 */ 48 static const char *non_simple_value_params[] = { 49 "CHAP_C", 50 "CHAP_R", 51 NULL, 52 }; 53 54 void 55 iscsi_param_free(struct iscsi_param *params) 56 { 57 struct iscsi_param *param, *next_param; 58 59 if (params == NULL) { 60 return; 61 } 62 for (param = params; param != NULL; param = next_param) { 63 next_param = param->next; 64 if (param->list) { 65 free(param->list); 66 } 67 free(param->val); 68 free(param->key); 69 free(param); 70 } 71 } 72 73 static int 74 iscsi_find_key_in_array(const char *key, const char *array[]) 75 { 76 int i; 77 78 for (i = 0; array[i] != NULL; i++) { 79 if (strcasecmp(key, array[i]) == 0) { 80 return 1; 81 } 82 } 83 return 0; 84 } 85 86 struct iscsi_param * 87 iscsi_param_find(struct iscsi_param *params, const char *key) 88 { 89 struct iscsi_param *param; 90 91 if (params == NULL || key == NULL) { 92 return NULL; 93 } 94 for (param = params; param != NULL; param = param->next) { 95 if (param->key != NULL && param->key[0] == key[0] 96 && strcasecmp(param->key, key) == 0) { 97 return param; 98 } 99 } 100 return NULL; 101 } 102 103 int 104 iscsi_param_del(struct iscsi_param **params, const char *key) 105 { 106 struct iscsi_param *param, *prev_param = NULL; 107 108 SPDK_DEBUGLOG(iscsi, "del %s\n", key); 109 if (params == NULL || key == NULL) { 110 return 0; 111 } 112 for (param = *params; param != NULL; param = param->next) { 113 if (param->key != NULL && param->key[0] == key[0] 114 && strcasecmp(param->key, key) == 0) { 115 if (prev_param != NULL) { 116 prev_param->next = param->next; 117 } else { 118 *params = param->next; 119 } 120 param->next = NULL; 121 iscsi_param_free(param); 122 return 0; 123 } 124 prev_param = param; 125 } 126 return -1; 127 } 128 129 int 130 iscsi_param_add(struct iscsi_param **params, const char *key, 131 const char *val, const char *list, int type) 132 { 133 struct iscsi_param *param, *last_param; 134 135 SPDK_DEBUGLOG(iscsi, "add %s=%s, list=[%s], type=%d\n", 136 key, val, list, type); 137 if (key == NULL) { 138 return -1; 139 } 140 141 param = iscsi_param_find(*params, key); 142 if (param != NULL) { 143 iscsi_param_del(params, key); 144 } 145 146 param = calloc(1, sizeof(*param)); 147 if (!param) { 148 SPDK_ERRLOG("calloc() failed for parameter\n"); 149 return -ENOMEM; 150 } 151 152 param->next = NULL; 153 param->key = xstrdup(key); 154 param->val = xstrdup(val); 155 param->list = xstrdup(list); 156 param->type = type; 157 158 last_param = *params; 159 if (last_param != NULL) { 160 while (last_param->next != NULL) { 161 last_param = last_param->next; 162 } 163 last_param->next = param; 164 } else { 165 *params = param; 166 } 167 168 return 0; 169 } 170 171 int 172 iscsi_param_set(struct iscsi_param *params, const char *key, 173 const char *val) 174 { 175 struct iscsi_param *param; 176 177 SPDK_DEBUGLOG(iscsi, "set %s=%s\n", key, val); 178 param = iscsi_param_find(params, key); 179 if (param == NULL) { 180 SPDK_ERRLOG("no key %s\n", key); 181 return -1; 182 } 183 184 free(param->val); 185 186 param->val = xstrdup(val); 187 188 return 0; 189 } 190 191 int 192 iscsi_param_set_int(struct iscsi_param *params, const char *key, uint32_t val) 193 { 194 char buf[MAX_TMPBUF]; 195 struct iscsi_param *param; 196 197 SPDK_DEBUGLOG(iscsi, "set %s=%d\n", key, val); 198 param = iscsi_param_find(params, key); 199 if (param == NULL) { 200 SPDK_ERRLOG("no key %s\n", key); 201 return -1; 202 } 203 204 free(param->val); 205 snprintf(buf, sizeof buf, "%d", val); 206 207 param->val = strdup(buf); 208 209 return 0; 210 } 211 212 /** 213 * Parse a single KEY=VAL pair 214 * 215 * data = "KEY=VAL<NUL>" 216 */ 217 static int 218 iscsi_parse_param(struct iscsi_param **params, const uint8_t *data, uint32_t data_len) 219 { 220 int rc; 221 uint8_t *key_copy, *val_copy; 222 const uint8_t *key_end; 223 int key_len, val_len; 224 int max_len; 225 226 data_len = strnlen(data, data_len); 227 /* No such thing as strnchr so use memchr instead. */ 228 key_end = memchr(data, '=', data_len); 229 if (!key_end) { 230 SPDK_ERRLOG("'=' not found\n"); 231 return -1; 232 } 233 234 key_len = key_end - data; 235 if (key_len == 0) { 236 SPDK_ERRLOG("Empty key\n"); 237 return -1; 238 } 239 /* 240 * RFC 7143 6.1 241 */ 242 if (key_len > ISCSI_TEXT_MAX_KEY_LEN) { 243 SPDK_ERRLOG("Key name length is bigger than 63\n"); 244 return -1; 245 } 246 247 key_copy = malloc(key_len + 1); 248 if (!key_copy) { 249 SPDK_ERRLOG("malloc() failed for key_copy\n"); 250 return -ENOMEM; 251 } 252 253 memcpy(key_copy, data, key_len); 254 key_copy[key_len] = '\0'; 255 /* check whether this key is duplicated */ 256 if (NULL != iscsi_param_find(*params, key_copy)) { 257 SPDK_ERRLOG("Duplicated Key %s\n", key_copy); 258 free(key_copy); 259 return -1; 260 } 261 262 val_len = strnlen(key_end + 1, data_len - key_len - 1); 263 /* 264 * RFC 3720 5.1 265 * If not otherwise specified, the maximum length of a simple-value 266 * (not its encoded representation) is 255 bytes, not including the delimiter 267 * (comma or zero byte). 268 */ 269 /* 270 * comma or zero is counted in, otherwise we need to iterate each parameter 271 * value 272 */ 273 max_len = iscsi_find_key_in_array(key_copy, non_simple_value_params) ? 274 ISCSI_TEXT_MAX_VAL_LEN : ISCSI_TEXT_MAX_SIMPLE_VAL_LEN; 275 if (val_len > max_len) { 276 SPDK_ERRLOG("Overflow Val %d\n", val_len); 277 free(key_copy); 278 return -1; 279 } 280 281 val_copy = calloc(1, val_len + 1); 282 if (val_copy == NULL) { 283 SPDK_ERRLOG("Could not allocate value string\n"); 284 free(key_copy); 285 return -1; 286 } 287 288 memcpy(val_copy, key_end + 1, val_len); 289 290 rc = iscsi_param_add(params, key_copy, val_copy, NULL, 0); 291 free(val_copy); 292 free(key_copy); 293 if (rc < 0) { 294 SPDK_ERRLOG("iscsi_param_add() failed\n"); 295 return -1; 296 } 297 298 /* return number of bytes consumed 299 * +1 for '=' and +1 for NUL 300 */ 301 return key_len + 1 + val_len + 1; 302 } 303 304 /** 305 * Parse a sequence of KEY=VAL pairs. 306 * 307 * \param data "KEY=VAL<NUL>KEY=VAL<NUL>..." 308 * \param len length of data in bytes 309 * 310 * Data must point to a valid pointer if len > 0. 311 */ 312 int 313 iscsi_parse_params(struct iscsi_param **params, const uint8_t *data, 314 int len, bool cbit_enabled, char **partial_parameter) 315 { 316 int rc, offset = 0; 317 char *p; 318 int i; 319 320 /* Spec does not disallow TEXT PDUs with zero length, just return 321 * immediately in that case, since there is no param data to parse 322 * and any existing partial parameter would remain as-is. 323 */ 324 if (len == 0) { 325 return 0; 326 } 327 328 assert(data != NULL); 329 330 /* strip the partial text parameters if previous PDU have C enabled */ 331 if (partial_parameter && *partial_parameter) { 332 for (i = 0; i < len && data[i] != '\0'; i++) { 333 ; 334 } 335 p = spdk_sprintf_alloc("%s%s", *partial_parameter, (const char *)data); 336 if (!p) { 337 return -1; 338 } 339 rc = iscsi_parse_param(params, p, i + strlen(*partial_parameter)); 340 free(p); 341 if (rc < 0) { 342 return -1; 343 } 344 free(*partial_parameter); 345 *partial_parameter = NULL; 346 347 data = data + i + 1; 348 len = len - (i + 1); 349 } 350 351 /* strip the partial text parameters if C bit is enabled */ 352 if (cbit_enabled) { 353 if (partial_parameter == NULL) { 354 SPDK_ERRLOG("C bit set but no partial parameters provided\n"); 355 return -1; 356 } 357 358 /* 359 * reverse iterate the string from the tail not including '\0' 360 */ 361 for (i = len - 1; data[i] != '\0' && i > 0; i--) { 362 ; 363 } 364 if (i != 0) { 365 /* We found a NULL character - don't copy it into the 366 * partial parameter. 367 */ 368 i++; 369 } 370 371 *partial_parameter = calloc(1, len - i + 1); 372 if (*partial_parameter == NULL) { 373 SPDK_ERRLOG("could not allocate partial parameter\n"); 374 return -1; 375 } 376 memcpy(*partial_parameter, &data[i], len - i); 377 if (i == 0) { 378 /* No full parameters to parse - so return now. */ 379 return 0; 380 } else { 381 len = i - 1; 382 } 383 } 384 385 while (offset < len && data[offset] != '\0') { 386 rc = iscsi_parse_param(params, data + offset, len - offset); 387 if (rc < 0) { 388 return -1; 389 } 390 offset += rc; 391 } 392 return 0; 393 } 394 395 char * 396 iscsi_param_get_val(struct iscsi_param *params, const char *key) 397 { 398 struct iscsi_param *param; 399 400 param = iscsi_param_find(params, key); 401 if (param == NULL) { 402 return NULL; 403 } 404 return param->val; 405 } 406 407 int 408 iscsi_param_eq_val(struct iscsi_param *params, const char *key, 409 const char *val) 410 { 411 struct iscsi_param *param; 412 413 param = iscsi_param_find(params, key); 414 if (param == NULL) { 415 return 0; 416 } 417 if (strcasecmp(param->val, val) == 0) { 418 return 1; 419 } 420 return 0; 421 } 422 423 struct iscsi_param_table { 424 const char *key; 425 const char *val; 426 const char *list; 427 int type; 428 }; 429 430 static const struct iscsi_param_table conn_param_table[] = { 431 { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST }, 432 { "DataDigest", "None", "CRC32C,None", ISPT_LIST }, 433 { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL_DECLARATIVE }, 434 { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 435 { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 436 { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 437 { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 438 { "AuthMethod", "None", "CHAP,None", ISPT_LIST }, 439 { "CHAP_A", "5", "5", ISPT_LIST }, 440 { "CHAP_N", "", "", ISPT_DECLARATIVE }, 441 { "CHAP_R", "", "", ISPT_DECLARATIVE }, 442 { "CHAP_I", "", "", ISPT_DECLARATIVE }, 443 { "CHAP_C", "", "", ISPT_DECLARATIVE }, 444 { NULL, NULL, NULL, ISPT_INVALID }, 445 }; 446 447 static const struct iscsi_param_table sess_param_table[] = { 448 { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL_MIN }, 449 #if 0 450 /* need special handling */ 451 { "SendTargets", "", "", ISPT_DECLARATIVE }, 452 #endif 453 { "TargetName", "", "", ISPT_DECLARATIVE }, 454 { "InitiatorName", "", "", ISPT_DECLARATIVE }, 455 { "TargetAlias", "", "", ISPT_DECLARATIVE }, 456 { "InitiatorAlias", "", "", ISPT_DECLARATIVE }, 457 { "TargetAddress", "", "", ISPT_DECLARATIVE }, 458 { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL_DECLARATIVE }, 459 { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 460 { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND }, 461 { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL_MIN }, 462 { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL_MIN }, 463 { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX }, 464 { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL_MIN }, 465 { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL_MIN }, 466 { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 467 { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 468 { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL_MIN }, 469 { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE }, 470 { NULL, NULL, NULL, ISPT_INVALID }, 471 }; 472 473 static int 474 iscsi_params_init_internal(struct iscsi_param **params, 475 const struct iscsi_param_table *table) 476 { 477 int rc; 478 int i; 479 struct iscsi_param *param; 480 481 for (i = 0; table[i].key != NULL; i++) { 482 rc = iscsi_param_add(params, table[i].key, table[i].val, 483 table[i].list, table[i].type); 484 if (rc < 0) { 485 SPDK_ERRLOG("iscsi_param_add() failed\n"); 486 return -1; 487 } 488 param = iscsi_param_find(*params, table[i].key); 489 if (param != NULL) { 490 param->state_index = i; 491 } else { 492 SPDK_ERRLOG("iscsi_param_find() failed\n"); 493 return -1; 494 } 495 } 496 497 return 0; 498 } 499 500 int 501 iscsi_conn_params_init(struct iscsi_param **params) 502 { 503 return iscsi_params_init_internal(params, &conn_param_table[0]); 504 } 505 506 int 507 iscsi_sess_params_init(struct iscsi_param **params) 508 { 509 return iscsi_params_init_internal(params, &sess_param_table[0]); 510 } 511 512 static const char *chap_type[] = { 513 "CHAP_A", 514 "CHAP_N", 515 "CHAP_R", 516 "CHAP_I", 517 "CHAP_C", 518 NULL, 519 }; 520 521 static const char *discovery_ignored_param[] = { 522 "MaxConnections", 523 "InitialR2T", 524 "ImmediateData", 525 "MaxBurstLength", 526 "FirstBurstLength" 527 "MaxOutstandingR2T", 528 "DataPDUInOrder", 529 "DataSequenceInOrder", 530 NULL, 531 }; 532 533 static const char *multi_negot_conn_params[] = { 534 "MaxRecvDataSegmentLength", 535 NULL, 536 }; 537 538 /* The following params should be declared by target */ 539 static const char *target_declarative_params[] = { 540 "TargetAlias", 541 "TargetAddress", 542 "TargetPortalGroupTag", 543 NULL, 544 }; 545 546 /* This function is used to construct the data from the special param (e.g., 547 * MaxRecvDataSegmentLength) 548 * return: 549 * normal: the total len of the data 550 * error: -1 551 */ 552 static int 553 iscsi_special_param_construction(struct spdk_iscsi_conn *conn, 554 struct iscsi_param *param, 555 bool FirstBurstLength_flag, char *data, 556 int alloc_len, int total) 557 { 558 int len; 559 struct iscsi_param *param_first; 560 struct iscsi_param *param_max; 561 uint32_t FirstBurstLength; 562 uint32_t MaxBurstLength; 563 char *val; 564 565 val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 566 if (!val) { 567 SPDK_ERRLOG("malloc() failed for temporary buffer\n"); 568 return -ENOMEM; 569 } 570 571 if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) { 572 /* 573 * MaxRecvDataSegmentLength is sent by both 574 * initiator and target, but is declarative - meaning 575 * each direction can have different values. 576 * So when MaxRecvDataSegmentLength is found in the 577 * the parameter set sent from the initiator, add SPDK 578 * iscsi target's MaxRecvDataSegmentLength value to 579 * the returned parameter list. 580 */ 581 if (alloc_len - total < 1) { 582 SPDK_ERRLOG("data space small %d\n", alloc_len); 583 free(val); 584 return -1; 585 } 586 587 SPDK_DEBUGLOG(iscsi, 588 "returning MaxRecvDataSegmentLength=%d\n", 589 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 590 len = snprintf((char *)data + total, alloc_len - total, 591 "MaxRecvDataSegmentLength=%d", 592 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 593 total += len + 1; 594 } 595 596 if (strcasecmp(param->key, "MaxBurstLength") == 0 && 597 !FirstBurstLength_flag) { 598 if (alloc_len - total < 1) { 599 SPDK_ERRLOG("data space small %d\n", alloc_len); 600 free(val); 601 return -1; 602 } 603 604 param_first = iscsi_param_find(conn->sess->params, 605 "FirstBurstLength"); 606 if (param_first != NULL) { 607 FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10); 608 } else { 609 FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 610 } 611 param_max = iscsi_param_find(conn->sess->params, 612 "MaxBurstLength"); 613 if (param_max != NULL) { 614 MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10); 615 } else { 616 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 617 } 618 619 if (FirstBurstLength > MaxBurstLength) { 620 FirstBurstLength = MaxBurstLength; 621 if (param_first != NULL) { 622 free(param_first->val); 623 snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 624 FirstBurstLength); 625 param_first->val = xstrdup(val); 626 } 627 } 628 len = snprintf((char *)data + total, alloc_len - total, 629 "FirstBurstLength=%d", FirstBurstLength); 630 total += len + 1; 631 } 632 633 free(val); 634 return total; 635 636 } 637 638 /** 639 * iscsi_construct_data_from_param: 640 * To construct the data which will be returned to the initiator 641 * return: length of the negotiated data, -1 indicates error; 642 */ 643 static int 644 iscsi_construct_data_from_param(struct iscsi_param *param, char *new_val, 645 char *data, int alloc_len, int total) 646 { 647 int len; 648 649 if (param->type != ISPT_DECLARATIVE && 650 param->type != ISPT_NUMERICAL_DECLARATIVE) { 651 if (alloc_len - total < 1) { 652 SPDK_ERRLOG("data space small %d\n", alloc_len); 653 return -1; 654 } 655 656 SPDK_DEBUGLOG(iscsi, "negotiated %s=%s\n", 657 param->key, new_val); 658 len = snprintf((char *)data + total, alloc_len - total, "%s=%s", 659 param->key, new_val); 660 total += len + 1; 661 } 662 return total; 663 } 664 665 /** 666 * To negotiate param with 667 * type = ISPT_LIST 668 * return: the negotiated value of the key 669 */ 670 static char * 671 iscsi_negotiate_param_list(int *add_param_value, 672 struct iscsi_param *param, 673 char *valid_list, char *in_val, 674 char *cur_val) 675 { 676 char *val_start, *val_end; 677 char *in_start, *in_end; 678 int flag = 0; 679 680 if (add_param_value == NULL) { 681 return NULL; 682 } 683 684 in_start = in_val; 685 do { 686 if ((in_end = strchr(in_start, (int)',')) != NULL) { 687 *in_end = '\0'; 688 } 689 val_start = valid_list; 690 do { 691 if ((val_end = strchr(val_start, (int)',')) != NULL) { 692 *val_end = '\0'; 693 } 694 if (strcasecmp(in_start, val_start) == 0) { 695 SPDK_DEBUGLOG(iscsi, "match %s\n", 696 val_start); 697 flag = 1; 698 break; 699 } 700 if (val_end) { 701 *val_end = ','; 702 val_start = val_end + 1; 703 } 704 } while (val_end); 705 if (flag) { 706 break; 707 } 708 if (in_end) { 709 *in_end = ','; 710 in_start = in_end + 1; 711 } 712 } while (in_end); 713 714 return flag ? val_start : NULL; 715 } 716 717 /** 718 * To negotiate param with 719 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE 720 * return: the negotiated value of the key 721 */ 722 static char * 723 iscsi_negotiate_param_numerical(int *add_param_value, 724 struct iscsi_param *param, 725 char *valid_list, char *in_val, 726 char *cur_val) 727 { 728 char *valid_next; 729 char *new_val = NULL; 730 char *min_val, *max_val; 731 int val_i, cur_val_i; 732 int min_i, max_i; 733 734 if (add_param_value == NULL) { 735 return NULL; 736 } 737 738 val_i = (int)strtol(param->val, NULL, 10); 739 /* check whether the key is FirstBurstLength, if that we use in_val */ 740 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 741 val_i = (int)strtol(in_val, NULL, 10); 742 } 743 744 cur_val_i = (int)strtol(cur_val, NULL, 10); 745 valid_next = valid_list; 746 min_val = spdk_strsepq(&valid_next, ","); 747 max_val = spdk_strsepq(&valid_next, ","); 748 min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0; 749 max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0; 750 if (val_i < min_i || val_i > max_i) { 751 SPDK_DEBUGLOG(iscsi, "key %.64s reject\n", param->key); 752 new_val = NULL; 753 } else { 754 switch (param->type) { 755 case ISPT_NUMERICAL_MIN: 756 if (val_i > cur_val_i) { 757 val_i = cur_val_i; 758 } 759 break; 760 case ISPT_NUMERICAL_MAX: 761 if (val_i < cur_val_i) { 762 val_i = cur_val_i; 763 } 764 break; 765 default: 766 break; 767 } 768 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); 769 new_val = in_val; 770 } 771 772 return new_val; 773 } 774 775 /** 776 * To negotiate param with 777 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND 778 * return: the negotiated value of the key 779 */ 780 static char * 781 iscsi_negotiate_param_boolean(int *add_param_value, 782 struct iscsi_param *param, 783 char *in_val, char *cur_val, 784 const char *value) 785 { 786 char *new_val = NULL; 787 788 if (add_param_value == NULL) { 789 return NULL; 790 } 791 792 /* Make sure the val is Yes or No */ 793 if (!((strcasecmp(in_val, "Yes") == 0) || 794 (strcasecmp(in_val, "No") == 0))) { 795 /* unknown value */ 796 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject"); 797 new_val = in_val; 798 *add_param_value = 1; 799 return new_val; 800 } 801 802 if (strcasecmp(cur_val, value) == 0) { 803 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value); 804 new_val = in_val; 805 } else { 806 new_val = param->val; 807 } 808 809 return new_val; 810 } 811 812 /** 813 * The entry function to handle each type of the param 814 * return value: the new negotiated value 815 */ 816 static char * 817 iscsi_negotiate_param_all(int *add_param_value, struct iscsi_param *param, 818 char *valid_list, char *in_val, char *cur_val) 819 { 820 char *new_val; 821 switch (param->type) { 822 case ISPT_LIST: 823 new_val = iscsi_negotiate_param_list(add_param_value, 824 param, 825 valid_list, 826 in_val, 827 cur_val); 828 break; 829 830 case ISPT_NUMERICAL_MIN: 831 case ISPT_NUMERICAL_MAX: 832 case ISPT_NUMERICAL_DECLARATIVE: 833 new_val = iscsi_negotiate_param_numerical(add_param_value, 834 param, 835 valid_list, 836 in_val, 837 cur_val); 838 break; 839 840 case ISPT_BOOLEAN_OR: 841 new_val = iscsi_negotiate_param_boolean(add_param_value, 842 param, 843 in_val, 844 cur_val, 845 "Yes"); 846 break; 847 case ISPT_BOOLEAN_AND: 848 new_val = iscsi_negotiate_param_boolean(add_param_value, 849 param, 850 in_val, 851 cur_val, 852 "No"); 853 break; 854 855 default: 856 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 857 new_val = in_val; 858 break; 859 } 860 861 return new_val; 862 } 863 864 /** 865 * This function is used to judge whether the param is in session's params or 866 * connection's params 867 */ 868 static int 869 iscsi_negotiate_param_init(struct spdk_iscsi_conn *conn, 870 struct iscsi_param **cur_param_p, 871 struct iscsi_param **params_dst_p, 872 struct iscsi_param *param) 873 { 874 int index; 875 876 *cur_param_p = iscsi_param_find(*params_dst_p, param->key); 877 if (*cur_param_p == NULL) { 878 *params_dst_p = conn->sess->params; 879 *cur_param_p = iscsi_param_find(*params_dst_p, param->key); 880 if (*cur_param_p == NULL) { 881 if ((strncasecmp(param->key, "X-", 2) == 0) || 882 (strncasecmp(param->key, "X#", 2) == 0)) { 883 /* Extension Key */ 884 SPDK_DEBUGLOG(iscsi, 885 "extension key %.64s\n", 886 param->key); 887 } else { 888 SPDK_ERRLOG("unknown key %.64s\n", param->key); 889 } 890 return 1; 891 } else { 892 index = (*cur_param_p)->state_index; 893 if (conn->sess_param_state_negotiated[index] && 894 !iscsi_find_key_in_array(param->key, 895 target_declarative_params)) { 896 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 897 } 898 conn->sess_param_state_negotiated[index] = true; 899 } 900 } else { 901 index = (*cur_param_p)->state_index; 902 if (conn->conn_param_state_negotiated[index] && 903 !iscsi_find_key_in_array(param->key, 904 multi_negot_conn_params)) { 905 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 906 } 907 conn->conn_param_state_negotiated[index] = true; 908 } 909 910 return 0; 911 } 912 913 int 914 iscsi_negotiate_params(struct spdk_iscsi_conn *conn, 915 struct iscsi_param **params, uint8_t *data, int alloc_len, 916 int data_len) 917 { 918 struct iscsi_param *param; 919 struct iscsi_param *cur_param; 920 char *valid_list, *in_val; 921 char *cur_val; 922 char *new_val; 923 int discovery; 924 int total; 925 int rc; 926 uint32_t FirstBurstLength; 927 uint32_t MaxBurstLength; 928 bool FirstBurstLength_flag = false; 929 int type; 930 931 total = data_len; 932 if (data_len < 0) { 933 assert(false); 934 return -EINVAL; 935 } 936 if (alloc_len < 1) { 937 return 0; 938 } 939 if (total > alloc_len) { 940 total = alloc_len; 941 data[total - 1] = '\0'; 942 return total; 943 } 944 945 if (*params == NULL) { 946 /* no input */ 947 return total; 948 } 949 950 /* discovery? */ 951 discovery = 0; 952 cur_param = iscsi_param_find(*params, "SessionType"); 953 if (cur_param == NULL) { 954 cur_param = iscsi_param_find(conn->sess->params, "SessionType"); 955 if (cur_param == NULL) { 956 /* no session type */ 957 } else { 958 if (strcasecmp(cur_param->val, "Discovery") == 0) { 959 discovery = 1; 960 } 961 } 962 } else { 963 if (strcasecmp(cur_param->val, "Discovery") == 0) { 964 discovery = 1; 965 } 966 } 967 968 /* for temporary store */ 969 valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 970 if (!valid_list) { 971 SPDK_ERRLOG("malloc() failed for valid_list\n"); 972 return -ENOMEM; 973 } 974 975 in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 976 if (!in_val) { 977 SPDK_ERRLOG("malloc() failed for in_val\n"); 978 free(valid_list); 979 return -ENOMEM; 980 } 981 982 cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 983 if (!cur_val) { 984 SPDK_ERRLOG("malloc() failed for cur_val\n"); 985 free(valid_list); 986 free(in_val); 987 return -ENOMEM; 988 } 989 990 /* To adjust the location of FirstBurstLength location and put it to 991 * the end, then we can always firstly determine the MaxBurstLength 992 */ 993 param = iscsi_param_find(*params, "MaxBurstLength"); 994 if (param != NULL) { 995 param = iscsi_param_find(*params, "FirstBurstLength"); 996 997 /* check the existence of FirstBurstLength */ 998 if (param != NULL) { 999 FirstBurstLength_flag = true; 1000 if (param->next != NULL) { 1001 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1002 type = param->type; 1003 iscsi_param_add(params, "FirstBurstLength", 1004 in_val, NULL, type); 1005 } 1006 } 1007 } 1008 1009 for (param = *params; param != NULL; param = param->next) { 1010 struct iscsi_param *params_dst = conn->params; 1011 int add_param_value = 0; 1012 new_val = NULL; 1013 param->type = ISPT_INVALID; 1014 1015 /* sendtargets is special */ 1016 if (strcasecmp(param->key, "SendTargets") == 0) { 1017 continue; 1018 } 1019 /* CHAP keys */ 1020 if (iscsi_find_key_in_array(param->key, chap_type)) { 1021 continue; 1022 } 1023 1024 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ 1025 if (discovery && 1026 iscsi_find_key_in_array(param->key, discovery_ignored_param)) { 1027 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant"); 1028 new_val = in_val; 1029 add_param_value = 1; 1030 } else { 1031 rc = iscsi_negotiate_param_init(conn, 1032 &cur_param, 1033 ¶ms_dst, 1034 param); 1035 if (rc < 0) { 1036 free(valid_list); 1037 free(in_val); 1038 free(cur_val); 1039 return rc; 1040 } else if (rc > 0) { 1041 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood"); 1042 new_val = in_val; 1043 add_param_value = 1; 1044 } else { 1045 snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list); 1046 snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val); 1047 param->type = cur_param->type; 1048 } 1049 } 1050 1051 if (param->type > 0) { 1052 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1053 1054 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */ 1055 if (strcasecmp(in_val, "NotUnderstood") == 0) { 1056 free(in_val); 1057 free(valid_list); 1058 free(cur_val); 1059 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER; 1060 } 1061 1062 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 1063 FirstBurstLength = (uint32_t)strtol(param->val, NULL, 1064 10); 1065 new_val = iscsi_param_get_val(conn->sess->params, 1066 "MaxBurstLength"); 1067 if (new_val != NULL) { 1068 MaxBurstLength = (uint32_t) strtol(new_val, NULL, 1069 10); 1070 } else { 1071 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 1072 } 1073 if (FirstBurstLength < SPDK_ISCSI_MAX_FIRST_BURST_LENGTH && 1074 FirstBurstLength > MaxBurstLength) { 1075 FirstBurstLength = MaxBurstLength; 1076 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 1077 FirstBurstLength); 1078 } 1079 } 1080 1081 /* prevent target's declarative params from being changed by initiator */ 1082 if (iscsi_find_key_in_array(param->key, target_declarative_params)) { 1083 add_param_value = 1; 1084 } 1085 1086 new_val = iscsi_negotiate_param_all(&add_param_value, 1087 param, 1088 valid_list, 1089 in_val, 1090 cur_val); 1091 } 1092 1093 /* check the negotiated value of the key */ 1094 if (new_val != NULL) { 1095 /* add_param_value = 0 means updating the value of 1096 * existed key in the connection's parameters 1097 */ 1098 if (add_param_value == 0) { 1099 iscsi_param_set(params_dst, param->key, new_val); 1100 } 1101 total = iscsi_construct_data_from_param(param, 1102 new_val, 1103 data, 1104 alloc_len, 1105 total); 1106 if (total < 0) { 1107 goto final_return; 1108 } 1109 1110 total = iscsi_special_param_construction(conn, 1111 param, 1112 FirstBurstLength_flag, 1113 data, 1114 alloc_len, 1115 total); 1116 if (total < 0) { 1117 goto final_return; 1118 } 1119 } else { 1120 total = -1; 1121 break; 1122 } 1123 } 1124 1125 final_return: 1126 free(valid_list); 1127 free(in_val); 1128 free(cur_val); 1129 1130 return total; 1131 } 1132 1133 int 1134 iscsi_copy_param2var(struct spdk_iscsi_conn *conn) 1135 { 1136 const char *val; 1137 1138 val = iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength"); 1139 if (val == NULL) { 1140 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n"); 1141 return -1; 1142 } 1143 SPDK_DEBUGLOG(iscsi, 1144 "copy MaxRecvDataSegmentLength=%s\n", val); 1145 conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); 1146 if (conn->MaxRecvDataSegmentLength > SPDK_BDEV_LARGE_BUF_MAX_SIZE) { 1147 conn->MaxRecvDataSegmentLength = SPDK_BDEV_LARGE_BUF_MAX_SIZE; 1148 } 1149 1150 val = iscsi_param_get_val(conn->params, "HeaderDigest"); 1151 if (val == NULL) { 1152 SPDK_ERRLOG("Getval HeaderDigest failed\n"); 1153 return -1; 1154 } 1155 if (strcasecmp(val, "CRC32C") == 0) { 1156 SPDK_DEBUGLOG(iscsi, "set HeaderDigest=1\n"); 1157 conn->header_digest = 1; 1158 } else { 1159 SPDK_DEBUGLOG(iscsi, "set HeaderDigest=0\n"); 1160 conn->header_digest = 0; 1161 } 1162 val = iscsi_param_get_val(conn->params, "DataDigest"); 1163 if (val == NULL) { 1164 SPDK_ERRLOG("Getval DataDigest failed\n"); 1165 return -1; 1166 } 1167 if (strcasecmp(val, "CRC32C") == 0) { 1168 SPDK_DEBUGLOG(iscsi, "set DataDigest=1\n"); 1169 conn->data_digest = 1; 1170 } else { 1171 SPDK_DEBUGLOG(iscsi, "set DataDigest=0\n"); 1172 conn->data_digest = 0; 1173 } 1174 1175 val = iscsi_param_get_val(conn->sess->params, "MaxConnections"); 1176 if (val == NULL) { 1177 SPDK_ERRLOG("Getval MaxConnections failed\n"); 1178 return -1; 1179 } 1180 SPDK_DEBUGLOG(iscsi, "copy MaxConnections=%s\n", val); 1181 conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10); 1182 val = iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T"); 1183 if (val == NULL) { 1184 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n"); 1185 return -1; 1186 } 1187 SPDK_DEBUGLOG(iscsi, "copy MaxOutstandingR2T=%s\n", val); 1188 conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10); 1189 val = iscsi_param_get_val(conn->sess->params, "FirstBurstLength"); 1190 if (val == NULL) { 1191 SPDK_ERRLOG("Getval FirstBurstLength failed\n"); 1192 return -1; 1193 } 1194 SPDK_DEBUGLOG(iscsi, "copy FirstBurstLength=%s\n", val); 1195 conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10); 1196 val = iscsi_param_get_val(conn->sess->params, "MaxBurstLength"); 1197 if (val == NULL) { 1198 SPDK_ERRLOG("Getval MaxBurstLength failed\n"); 1199 return -1; 1200 } 1201 SPDK_DEBUGLOG(iscsi, "copy MaxBurstLength=%s\n", val); 1202 conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10); 1203 val = iscsi_param_get_val(conn->sess->params, "InitialR2T"); 1204 if (val == NULL) { 1205 SPDK_ERRLOG("Getval InitialR2T failed\n"); 1206 return -1; 1207 } 1208 if (strcasecmp(val, "Yes") == 0) { 1209 SPDK_DEBUGLOG(iscsi, "set InitialR2T=1\n"); 1210 conn->sess->InitialR2T = true; 1211 } else { 1212 SPDK_DEBUGLOG(iscsi, "set InitialR2T=0\n"); 1213 conn->sess->InitialR2T = false; 1214 } 1215 val = iscsi_param_get_val(conn->sess->params, "ImmediateData"); 1216 if (val == NULL) { 1217 SPDK_ERRLOG("Getval ImmediateData failed\n"); 1218 return -1; 1219 } 1220 if (strcasecmp(val, "Yes") == 0) { 1221 SPDK_DEBUGLOG(iscsi, "set ImmediateData=1\n"); 1222 conn->sess->ImmediateData = true; 1223 } else { 1224 SPDK_DEBUGLOG(iscsi, "set ImmediateData=0\n"); 1225 conn->sess->ImmediateData = false; 1226 } 1227 return 0; 1228 } 1229