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 int 311 iscsi_parse_params(struct iscsi_param **params, const uint8_t *data, 312 int len, bool cbit_enabled, char **partial_parameter) 313 { 314 int rc, offset = 0; 315 char *p; 316 int i; 317 318 /* strip the partial text parameters if previous PDU have C enabled */ 319 if (partial_parameter && *partial_parameter) { 320 for (i = 0; i < len && data[i] != '\0'; i++) { 321 ; 322 } 323 p = spdk_sprintf_alloc("%s%s", *partial_parameter, (const char *)data); 324 if (!p) { 325 return -1; 326 } 327 rc = iscsi_parse_param(params, p, i + strlen(*partial_parameter)); 328 free(p); 329 if (rc < 0) { 330 return -1; 331 } 332 free(*partial_parameter); 333 *partial_parameter = NULL; 334 335 data = data + i + 1; 336 len = len - (i + 1); 337 } 338 339 /* strip the partial text parameters if C bit is enabled */ 340 if (cbit_enabled) { 341 if (partial_parameter == NULL) { 342 SPDK_ERRLOG("C bit set but no partial parameters provided\n"); 343 return -1; 344 } 345 346 /* 347 * reverse iterate the string from the tail not including '\0' 348 */ 349 for (i = len - 1; data[i] != '\0' && i > 0; i--) { 350 ; 351 } 352 if (i != 0) { 353 /* We found a NULL character - don't copy it into the 354 * partial parameter. 355 */ 356 i++; 357 } 358 359 *partial_parameter = calloc(1, len - i + 1); 360 if (*partial_parameter == NULL) { 361 SPDK_ERRLOG("could not allocate partial parameter\n"); 362 return -1; 363 } 364 memcpy(*partial_parameter, &data[i], len - i); 365 if (i == 0) { 366 /* No full parameters to parse - so return now. */ 367 return 0; 368 } else { 369 len = i - 1; 370 } 371 } 372 373 while (offset < len && data[offset] != '\0') { 374 rc = iscsi_parse_param(params, data + offset, len - offset); 375 if (rc < 0) { 376 return -1; 377 } 378 offset += rc; 379 } 380 return 0; 381 } 382 383 char * 384 iscsi_param_get_val(struct iscsi_param *params, const char *key) 385 { 386 struct iscsi_param *param; 387 388 param = iscsi_param_find(params, key); 389 if (param == NULL) { 390 return NULL; 391 } 392 return param->val; 393 } 394 395 int 396 iscsi_param_eq_val(struct iscsi_param *params, const char *key, 397 const char *val) 398 { 399 struct iscsi_param *param; 400 401 param = iscsi_param_find(params, key); 402 if (param == NULL) { 403 return 0; 404 } 405 if (strcasecmp(param->val, val) == 0) { 406 return 1; 407 } 408 return 0; 409 } 410 411 struct iscsi_param_table { 412 const char *key; 413 const char *val; 414 const char *list; 415 int type; 416 }; 417 418 static const struct iscsi_param_table conn_param_table[] = { 419 { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST }, 420 { "DataDigest", "None", "CRC32C,None", ISPT_LIST }, 421 { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL_DECLARATIVE }, 422 { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 423 { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 424 { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 425 { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 426 { "AuthMethod", "None", "CHAP,None", ISPT_LIST }, 427 { "CHAP_A", "5", "5", ISPT_LIST }, 428 { "CHAP_N", "", "", ISPT_DECLARATIVE }, 429 { "CHAP_R", "", "", ISPT_DECLARATIVE }, 430 { "CHAP_I", "", "", ISPT_DECLARATIVE }, 431 { "CHAP_C", "", "", ISPT_DECLARATIVE }, 432 { NULL, NULL, NULL, ISPT_INVALID }, 433 }; 434 435 static const struct iscsi_param_table sess_param_table[] = { 436 { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL_MIN }, 437 #if 0 438 /* need special handling */ 439 { "SendTargets", "", "", ISPT_DECLARATIVE }, 440 #endif 441 { "TargetName", "", "", ISPT_DECLARATIVE }, 442 { "InitiatorName", "", "", ISPT_DECLARATIVE }, 443 { "TargetAlias", "", "", ISPT_DECLARATIVE }, 444 { "InitiatorAlias", "", "", ISPT_DECLARATIVE }, 445 { "TargetAddress", "", "", ISPT_DECLARATIVE }, 446 { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL_DECLARATIVE }, 447 { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 448 { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND }, 449 { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL_MIN }, 450 { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL_MIN }, 451 { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX }, 452 { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL_MIN }, 453 { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL_MIN }, 454 { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 455 { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 456 { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL_MIN }, 457 { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE }, 458 { NULL, NULL, NULL, ISPT_INVALID }, 459 }; 460 461 static int 462 iscsi_params_init_internal(struct iscsi_param **params, 463 const struct iscsi_param_table *table) 464 { 465 int rc; 466 int i; 467 struct iscsi_param *param; 468 469 for (i = 0; table[i].key != NULL; i++) { 470 rc = iscsi_param_add(params, table[i].key, table[i].val, 471 table[i].list, table[i].type); 472 if (rc < 0) { 473 SPDK_ERRLOG("iscsi_param_add() failed\n"); 474 return -1; 475 } 476 param = iscsi_param_find(*params, table[i].key); 477 if (param != NULL) { 478 param->state_index = i; 479 } else { 480 SPDK_ERRLOG("iscsi_param_find() failed\n"); 481 return -1; 482 } 483 } 484 485 return 0; 486 } 487 488 int 489 iscsi_conn_params_init(struct iscsi_param **params) 490 { 491 return iscsi_params_init_internal(params, &conn_param_table[0]); 492 } 493 494 int 495 iscsi_sess_params_init(struct iscsi_param **params) 496 { 497 return iscsi_params_init_internal(params, &sess_param_table[0]); 498 } 499 500 static const char *chap_type[] = { 501 "CHAP_A", 502 "CHAP_N", 503 "CHAP_R", 504 "CHAP_I", 505 "CHAP_C", 506 NULL, 507 }; 508 509 static const char *discovery_ignored_param[] = { 510 "MaxConnections", 511 "InitialR2T", 512 "ImmediateData", 513 "MaxBurstLength", 514 "FirstBurstLength" 515 "MaxOutstandingR2T", 516 "DataPDUInOrder", 517 "DataSequenceInOrder", 518 NULL, 519 }; 520 521 static const char *multi_negot_conn_params[] = { 522 "MaxRecvDataSegmentLength", 523 NULL, 524 }; 525 526 /* The following params should be declared by target */ 527 static const char *target_declarative_params[] = { 528 "TargetAlias", 529 "TargetAddress", 530 "TargetPortalGroupTag", 531 NULL, 532 }; 533 534 /* This function is used to construct the data from the special param (e.g., 535 * MaxRecvDataSegmentLength) 536 * return: 537 * normal: the total len of the data 538 * error: -1 539 */ 540 static int 541 iscsi_special_param_construction(struct spdk_iscsi_conn *conn, 542 struct iscsi_param *param, 543 bool FirstBurstLength_flag, char *data, 544 int alloc_len, int total) 545 { 546 int len; 547 struct iscsi_param *param_first; 548 struct iscsi_param *param_max; 549 uint32_t FirstBurstLength; 550 uint32_t MaxBurstLength; 551 char *val; 552 553 val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 554 if (!val) { 555 SPDK_ERRLOG("malloc() failed for temporary buffer\n"); 556 return -ENOMEM; 557 } 558 559 if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) { 560 /* 561 * MaxRecvDataSegmentLength is sent by both 562 * initiator and target, but is declarative - meaning 563 * each direction can have different values. 564 * So when MaxRecvDataSegmentLength is found in the 565 * the parameter set sent from the initiator, add SPDK 566 * iscsi target's MaxRecvDataSegmentLength value to 567 * the returned parameter list. 568 */ 569 if (alloc_len - total < 1) { 570 SPDK_ERRLOG("data space small %d\n", alloc_len); 571 free(val); 572 return -1; 573 } 574 575 SPDK_DEBUGLOG(iscsi, 576 "returning MaxRecvDataSegmentLength=%d\n", 577 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 578 len = snprintf((char *)data + total, alloc_len - total, 579 "MaxRecvDataSegmentLength=%d", 580 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 581 total += len + 1; 582 } 583 584 if (strcasecmp(param->key, "MaxBurstLength") == 0 && 585 !FirstBurstLength_flag) { 586 if (alloc_len - total < 1) { 587 SPDK_ERRLOG("data space small %d\n", alloc_len); 588 free(val); 589 return -1; 590 } 591 592 param_first = iscsi_param_find(conn->sess->params, 593 "FirstBurstLength"); 594 if (param_first != NULL) { 595 FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10); 596 } else { 597 FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 598 } 599 param_max = iscsi_param_find(conn->sess->params, 600 "MaxBurstLength"); 601 if (param_max != NULL) { 602 MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10); 603 } else { 604 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 605 } 606 607 if (FirstBurstLength > MaxBurstLength) { 608 FirstBurstLength = MaxBurstLength; 609 if (param_first != NULL) { 610 free(param_first->val); 611 snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 612 FirstBurstLength); 613 param_first->val = xstrdup(val); 614 } 615 } 616 len = snprintf((char *)data + total, alloc_len - total, 617 "FirstBurstLength=%d", FirstBurstLength); 618 total += len + 1; 619 } 620 621 free(val); 622 return total; 623 624 } 625 626 /** 627 * iscsi_construct_data_from_param: 628 * To construct the data which will be returned to the initiator 629 * return: length of the negotiated data, -1 indicates error; 630 */ 631 static int 632 iscsi_construct_data_from_param(struct iscsi_param *param, char *new_val, 633 char *data, int alloc_len, int total) 634 { 635 int len; 636 637 if (param->type != ISPT_DECLARATIVE && 638 param->type != ISPT_NUMERICAL_DECLARATIVE) { 639 if (alloc_len - total < 1) { 640 SPDK_ERRLOG("data space small %d\n", alloc_len); 641 return -1; 642 } 643 644 SPDK_DEBUGLOG(iscsi, "negotiated %s=%s\n", 645 param->key, new_val); 646 len = snprintf((char *)data + total, alloc_len - total, "%s=%s", 647 param->key, new_val); 648 total += len + 1; 649 } 650 return total; 651 } 652 653 /** 654 * To negotiate param with 655 * type = ISPT_LIST 656 * return: the negotiated value of the key 657 */ 658 static char * 659 iscsi_negotiate_param_list(int *add_param_value, 660 struct iscsi_param *param, 661 char *valid_list, char *in_val, 662 char *cur_val) 663 { 664 char *val_start, *val_end; 665 char *in_start, *in_end; 666 int flag = 0; 667 668 if (add_param_value == NULL) { 669 return NULL; 670 } 671 672 in_start = in_val; 673 do { 674 if ((in_end = strchr(in_start, (int)',')) != NULL) { 675 *in_end = '\0'; 676 } 677 val_start = valid_list; 678 do { 679 if ((val_end = strchr(val_start, (int)',')) != NULL) { 680 *val_end = '\0'; 681 } 682 if (strcasecmp(in_start, val_start) == 0) { 683 SPDK_DEBUGLOG(iscsi, "match %s\n", 684 val_start); 685 flag = 1; 686 break; 687 } 688 if (val_end) { 689 *val_end = ','; 690 val_start = val_end + 1; 691 } 692 } while (val_end); 693 if (flag) { 694 break; 695 } 696 if (in_end) { 697 *in_end = ','; 698 in_start = in_end + 1; 699 } 700 } while (in_end); 701 702 return flag ? val_start : NULL; 703 } 704 705 /** 706 * To negotiate param with 707 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE 708 * return: the negotiated value of the key 709 */ 710 static char * 711 iscsi_negotiate_param_numerical(int *add_param_value, 712 struct iscsi_param *param, 713 char *valid_list, char *in_val, 714 char *cur_val) 715 { 716 char *valid_next; 717 char *new_val = NULL; 718 char *min_val, *max_val; 719 int val_i, cur_val_i; 720 int min_i, max_i; 721 722 if (add_param_value == NULL) { 723 return NULL; 724 } 725 726 val_i = (int)strtol(param->val, NULL, 10); 727 /* check whether the key is FirstBurstLength, if that we use in_val */ 728 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 729 val_i = (int)strtol(in_val, NULL, 10); 730 } 731 732 cur_val_i = (int)strtol(cur_val, NULL, 10); 733 valid_next = valid_list; 734 min_val = spdk_strsepq(&valid_next, ","); 735 max_val = spdk_strsepq(&valid_next, ","); 736 min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0; 737 max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0; 738 if (val_i < min_i || val_i > max_i) { 739 SPDK_DEBUGLOG(iscsi, "key %.64s reject\n", param->key); 740 new_val = NULL; 741 } else { 742 switch (param->type) { 743 case ISPT_NUMERICAL_MIN: 744 if (val_i > cur_val_i) { 745 val_i = cur_val_i; 746 } 747 break; 748 case ISPT_NUMERICAL_MAX: 749 if (val_i < cur_val_i) { 750 val_i = cur_val_i; 751 } 752 break; 753 default: 754 break; 755 } 756 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); 757 new_val = in_val; 758 } 759 760 return new_val; 761 } 762 763 /** 764 * To negotiate param with 765 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND 766 * return: the negotiated value of the key 767 */ 768 static char * 769 iscsi_negotiate_param_boolean(int *add_param_value, 770 struct iscsi_param *param, 771 char *in_val, char *cur_val, 772 const char *value) 773 { 774 char *new_val = NULL; 775 776 if (add_param_value == NULL) { 777 return NULL; 778 } 779 780 /* Make sure the val is Yes or No */ 781 if (!((strcasecmp(in_val, "Yes") == 0) || 782 (strcasecmp(in_val, "No") == 0))) { 783 /* unknown value */ 784 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject"); 785 new_val = in_val; 786 *add_param_value = 1; 787 return new_val; 788 } 789 790 if (strcasecmp(cur_val, value) == 0) { 791 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value); 792 new_val = in_val; 793 } else { 794 new_val = param->val; 795 } 796 797 return new_val; 798 } 799 800 /** 801 * The entry function to handle each type of the param 802 * return value: the new negotiated value 803 */ 804 static char * 805 iscsi_negotiate_param_all(int *add_param_value, struct iscsi_param *param, 806 char *valid_list, char *in_val, char *cur_val) 807 { 808 char *new_val; 809 switch (param->type) { 810 case ISPT_LIST: 811 new_val = iscsi_negotiate_param_list(add_param_value, 812 param, 813 valid_list, 814 in_val, 815 cur_val); 816 break; 817 818 case ISPT_NUMERICAL_MIN: 819 case ISPT_NUMERICAL_MAX: 820 case ISPT_NUMERICAL_DECLARATIVE: 821 new_val = iscsi_negotiate_param_numerical(add_param_value, 822 param, 823 valid_list, 824 in_val, 825 cur_val); 826 break; 827 828 case ISPT_BOOLEAN_OR: 829 new_val = iscsi_negotiate_param_boolean(add_param_value, 830 param, 831 in_val, 832 cur_val, 833 "Yes"); 834 break; 835 case ISPT_BOOLEAN_AND: 836 new_val = iscsi_negotiate_param_boolean(add_param_value, 837 param, 838 in_val, 839 cur_val, 840 "No"); 841 break; 842 843 default: 844 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 845 new_val = in_val; 846 break; 847 } 848 849 return new_val; 850 } 851 852 /** 853 * This function is used to judge whether the param is in session's params or 854 * connection's params 855 */ 856 static int 857 iscsi_negotiate_param_init(struct spdk_iscsi_conn *conn, 858 struct iscsi_param **cur_param_p, 859 struct iscsi_param **params_dst_p, 860 struct iscsi_param *param) 861 { 862 int index; 863 864 *cur_param_p = iscsi_param_find(*params_dst_p, param->key); 865 if (*cur_param_p == NULL) { 866 *params_dst_p = conn->sess->params; 867 *cur_param_p = iscsi_param_find(*params_dst_p, param->key); 868 if (*cur_param_p == NULL) { 869 if ((strncasecmp(param->key, "X-", 2) == 0) || 870 (strncasecmp(param->key, "X#", 2) == 0)) { 871 /* Extension Key */ 872 SPDK_DEBUGLOG(iscsi, 873 "extension key %.64s\n", 874 param->key); 875 } else { 876 SPDK_ERRLOG("unknown key %.64s\n", param->key); 877 } 878 return 1; 879 } else { 880 index = (*cur_param_p)->state_index; 881 if (conn->sess_param_state_negotiated[index] && 882 !iscsi_find_key_in_array(param->key, 883 target_declarative_params)) { 884 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 885 } 886 conn->sess_param_state_negotiated[index] = true; 887 } 888 } else { 889 index = (*cur_param_p)->state_index; 890 if (conn->conn_param_state_negotiated[index] && 891 !iscsi_find_key_in_array(param->key, 892 multi_negot_conn_params)) { 893 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 894 } 895 conn->conn_param_state_negotiated[index] = true; 896 } 897 898 return 0; 899 } 900 901 int 902 iscsi_negotiate_params(struct spdk_iscsi_conn *conn, 903 struct iscsi_param **params, uint8_t *data, int alloc_len, 904 int data_len) 905 { 906 struct iscsi_param *param; 907 struct iscsi_param *cur_param; 908 char *valid_list, *in_val; 909 char *cur_val; 910 char *new_val; 911 int discovery; 912 int total; 913 int rc; 914 uint32_t FirstBurstLength; 915 uint32_t MaxBurstLength; 916 bool FirstBurstLength_flag = false; 917 int type; 918 919 total = data_len; 920 if (data_len < 0) { 921 assert(false); 922 return -EINVAL; 923 } 924 if (alloc_len < 1) { 925 return 0; 926 } 927 if (total > alloc_len) { 928 total = alloc_len; 929 data[total - 1] = '\0'; 930 return total; 931 } 932 933 if (*params == NULL) { 934 /* no input */ 935 return total; 936 } 937 938 /* discovery? */ 939 discovery = 0; 940 cur_param = iscsi_param_find(*params, "SessionType"); 941 if (cur_param == NULL) { 942 cur_param = iscsi_param_find(conn->sess->params, "SessionType"); 943 if (cur_param == NULL) { 944 /* no session type */ 945 } else { 946 if (strcasecmp(cur_param->val, "Discovery") == 0) { 947 discovery = 1; 948 } 949 } 950 } else { 951 if (strcasecmp(cur_param->val, "Discovery") == 0) { 952 discovery = 1; 953 } 954 } 955 956 /* for temporary store */ 957 valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 958 if (!valid_list) { 959 SPDK_ERRLOG("malloc() failed for valid_list\n"); 960 return -ENOMEM; 961 } 962 963 in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 964 if (!in_val) { 965 SPDK_ERRLOG("malloc() failed for in_val\n"); 966 free(valid_list); 967 return -ENOMEM; 968 } 969 970 cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 971 if (!cur_val) { 972 SPDK_ERRLOG("malloc() failed for cur_val\n"); 973 free(valid_list); 974 free(in_val); 975 return -ENOMEM; 976 } 977 978 /* To adjust the location of FirstBurstLength location and put it to 979 * the end, then we can always firstly determine the MaxBurstLength 980 */ 981 param = iscsi_param_find(*params, "MaxBurstLength"); 982 if (param != NULL) { 983 param = iscsi_param_find(*params, "FirstBurstLength"); 984 985 /* check the existence of FirstBurstLength */ 986 if (param != NULL) { 987 FirstBurstLength_flag = true; 988 if (param->next != NULL) { 989 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 990 type = param->type; 991 iscsi_param_add(params, "FirstBurstLength", 992 in_val, NULL, type); 993 } 994 } 995 } 996 997 for (param = *params; param != NULL; param = param->next) { 998 struct iscsi_param *params_dst = conn->params; 999 int add_param_value = 0; 1000 new_val = NULL; 1001 param->type = ISPT_INVALID; 1002 1003 /* sendtargets is special */ 1004 if (strcasecmp(param->key, "SendTargets") == 0) { 1005 continue; 1006 } 1007 /* CHAP keys */ 1008 if (iscsi_find_key_in_array(param->key, chap_type)) { 1009 continue; 1010 } 1011 1012 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ 1013 if (discovery && 1014 iscsi_find_key_in_array(param->key, discovery_ignored_param)) { 1015 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant"); 1016 new_val = in_val; 1017 add_param_value = 1; 1018 } else { 1019 rc = iscsi_negotiate_param_init(conn, 1020 &cur_param, 1021 ¶ms_dst, 1022 param); 1023 if (rc < 0) { 1024 free(valid_list); 1025 free(in_val); 1026 free(cur_val); 1027 return rc; 1028 } else if (rc > 0) { 1029 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood"); 1030 new_val = in_val; 1031 add_param_value = 1; 1032 } else { 1033 snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list); 1034 snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val); 1035 param->type = cur_param->type; 1036 } 1037 } 1038 1039 if (param->type > 0) { 1040 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1041 1042 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */ 1043 if (strcasecmp(in_val, "NotUnderstood") == 0) { 1044 free(in_val); 1045 free(valid_list); 1046 free(cur_val); 1047 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER; 1048 } 1049 1050 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 1051 FirstBurstLength = (uint32_t)strtol(param->val, NULL, 1052 10); 1053 new_val = iscsi_param_get_val(conn->sess->params, 1054 "MaxBurstLength"); 1055 if (new_val != NULL) { 1056 MaxBurstLength = (uint32_t) strtol(new_val, NULL, 1057 10); 1058 } else { 1059 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 1060 } 1061 if (FirstBurstLength < SPDK_ISCSI_MAX_FIRST_BURST_LENGTH && 1062 FirstBurstLength > MaxBurstLength) { 1063 FirstBurstLength = MaxBurstLength; 1064 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 1065 FirstBurstLength); 1066 } 1067 } 1068 1069 /* prevent target's declarative params from being changed by initiator */ 1070 if (iscsi_find_key_in_array(param->key, target_declarative_params)) { 1071 add_param_value = 1; 1072 } 1073 1074 new_val = iscsi_negotiate_param_all(&add_param_value, 1075 param, 1076 valid_list, 1077 in_val, 1078 cur_val); 1079 } 1080 1081 /* check the negotiated value of the key */ 1082 if (new_val != NULL) { 1083 /* add_param_value = 0 means updating the value of 1084 * existed key in the connection's parameters 1085 */ 1086 if (add_param_value == 0) { 1087 iscsi_param_set(params_dst, param->key, new_val); 1088 } 1089 total = iscsi_construct_data_from_param(param, 1090 new_val, 1091 data, 1092 alloc_len, 1093 total); 1094 if (total < 0) { 1095 goto final_return; 1096 } 1097 1098 total = iscsi_special_param_construction(conn, 1099 param, 1100 FirstBurstLength_flag, 1101 data, 1102 alloc_len, 1103 total); 1104 if (total < 0) { 1105 goto final_return; 1106 } 1107 } else { 1108 total = -1; 1109 break; 1110 } 1111 } 1112 1113 final_return: 1114 free(valid_list); 1115 free(in_val); 1116 free(cur_val); 1117 1118 return total; 1119 } 1120 1121 int 1122 iscsi_copy_param2var(struct spdk_iscsi_conn *conn) 1123 { 1124 const char *val; 1125 1126 val = iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength"); 1127 if (val == NULL) { 1128 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n"); 1129 return -1; 1130 } 1131 SPDK_DEBUGLOG(iscsi, 1132 "copy MaxRecvDataSegmentLength=%s\n", val); 1133 conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); 1134 if (conn->MaxRecvDataSegmentLength > SPDK_BDEV_LARGE_BUF_MAX_SIZE) { 1135 conn->MaxRecvDataSegmentLength = SPDK_BDEV_LARGE_BUF_MAX_SIZE; 1136 } 1137 1138 val = iscsi_param_get_val(conn->params, "HeaderDigest"); 1139 if (val == NULL) { 1140 SPDK_ERRLOG("Getval HeaderDigest failed\n"); 1141 return -1; 1142 } 1143 if (strcasecmp(val, "CRC32C") == 0) { 1144 SPDK_DEBUGLOG(iscsi, "set HeaderDigest=1\n"); 1145 conn->header_digest = 1; 1146 } else { 1147 SPDK_DEBUGLOG(iscsi, "set HeaderDigest=0\n"); 1148 conn->header_digest = 0; 1149 } 1150 val = iscsi_param_get_val(conn->params, "DataDigest"); 1151 if (val == NULL) { 1152 SPDK_ERRLOG("Getval DataDigest failed\n"); 1153 return -1; 1154 } 1155 if (strcasecmp(val, "CRC32C") == 0) { 1156 SPDK_DEBUGLOG(iscsi, "set DataDigest=1\n"); 1157 conn->data_digest = 1; 1158 } else { 1159 SPDK_DEBUGLOG(iscsi, "set DataDigest=0\n"); 1160 conn->data_digest = 0; 1161 } 1162 1163 val = iscsi_param_get_val(conn->sess->params, "MaxConnections"); 1164 if (val == NULL) { 1165 SPDK_ERRLOG("Getval MaxConnections failed\n"); 1166 return -1; 1167 } 1168 SPDK_DEBUGLOG(iscsi, "copy MaxConnections=%s\n", val); 1169 conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10); 1170 val = iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T"); 1171 if (val == NULL) { 1172 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n"); 1173 return -1; 1174 } 1175 SPDK_DEBUGLOG(iscsi, "copy MaxOutstandingR2T=%s\n", val); 1176 conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10); 1177 val = iscsi_param_get_val(conn->sess->params, "FirstBurstLength"); 1178 if (val == NULL) { 1179 SPDK_ERRLOG("Getval FirstBurstLength failed\n"); 1180 return -1; 1181 } 1182 SPDK_DEBUGLOG(iscsi, "copy FirstBurstLength=%s\n", val); 1183 conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10); 1184 val = iscsi_param_get_val(conn->sess->params, "MaxBurstLength"); 1185 if (val == NULL) { 1186 SPDK_ERRLOG("Getval MaxBurstLength failed\n"); 1187 return -1; 1188 } 1189 SPDK_DEBUGLOG(iscsi, "copy MaxBurstLength=%s\n", val); 1190 conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10); 1191 val = iscsi_param_get_val(conn->sess->params, "InitialR2T"); 1192 if (val == NULL) { 1193 SPDK_ERRLOG("Getval InitialR2T failed\n"); 1194 return -1; 1195 } 1196 if (strcasecmp(val, "Yes") == 0) { 1197 SPDK_DEBUGLOG(iscsi, "set InitialR2T=1\n"); 1198 conn->sess->InitialR2T = true; 1199 } else { 1200 SPDK_DEBUGLOG(iscsi, "set InitialR2T=0\n"); 1201 conn->sess->InitialR2T = false; 1202 } 1203 val = iscsi_param_get_val(conn->sess->params, "ImmediateData"); 1204 if (val == NULL) { 1205 SPDK_ERRLOG("Getval ImmediateData failed\n"); 1206 return -1; 1207 } 1208 if (strcasecmp(val, "Yes") == 0) { 1209 SPDK_DEBUGLOG(iscsi, "set ImmediateData=1\n"); 1210 conn->sess->ImmediateData = true; 1211 } else { 1212 SPDK_DEBUGLOG(iscsi, "set ImmediateData=0\n"); 1213 conn->sess->ImmediateData = false; 1214 } 1215 return 0; 1216 } 1217