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