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_internal/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 spdk_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 spdk_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 spdk_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 spdk_iscsi_param_del(struct iscsi_param **params, const char *key) 105 { 106 struct iscsi_param *param, *prev_param = NULL; 107 108 SPDK_DEBUGLOG(SPDK_LOG_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 spdk_iscsi_param_free(param); 122 return 0; 123 } 124 prev_param = param; 125 } 126 return -1; 127 } 128 129 int 130 spdk_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(SPDK_LOG_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 = spdk_iscsi_param_find(*params, key); 142 if (param != NULL) { 143 spdk_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 spdk_iscsi_param_set(struct iscsi_param *params, const char *key, 173 const char *val) 174 { 175 struct iscsi_param *param; 176 177 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set %s=%s\n", key, val); 178 param = spdk_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 spdk_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(SPDK_LOG_ISCSI, "set %s=%d\n", key, val); 198 param = spdk_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 spdk_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 != spdk_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 = spdk_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 = spdk_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 spdk_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 = spdk_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 = spdk_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 spdk_iscsi_param_get_val(struct iscsi_param *params, const char *key) 385 { 386 struct iscsi_param *param; 387 388 param = spdk_iscsi_param_find(params, key); 389 if (param == NULL) { 390 return NULL; 391 } 392 return param->val; 393 } 394 395 int 396 spdk_iscsi_param_eq_val(struct iscsi_param *params, const char *key, 397 const char *val) 398 { 399 struct iscsi_param *param; 400 401 param = spdk_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 spdk_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 = spdk_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 = spdk_iscsi_param_find(*params, table[i].key); 477 if (param != NULL) { 478 param->state_index = i; 479 } else { 480 SPDK_ERRLOG("spdk_iscsi_param_find() failed\n"); 481 return -1; 482 } 483 } 484 485 return 0; 486 } 487 488 int 489 spdk_iscsi_conn_params_init(struct iscsi_param **params) 490 { 491 return spdk_iscsi_params_init_internal(params, &conn_param_table[0]); 492 } 493 494 int 495 spdk_iscsi_sess_params_init(struct iscsi_param **params) 496 { 497 return spdk_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 NULL, 518 }; 519 520 static const char *multi_negot_conn_params[] = { 521 "MaxRecvDataSegmentLength", 522 NULL, 523 }; 524 525 /* The following params should be declared by target */ 526 static const char *target_declarative_params[] = { 527 "TargetAlias", 528 "TargetAddress", 529 "TargetPortalGroupTag", 530 NULL, 531 }; 532 533 /* This function is used to construct the data from the special param (e.g., 534 * MaxRecvDataSegmentLength) 535 * return: 536 * normal: the total len of the data 537 * error: -1 538 */ 539 static int 540 spdk_iscsi_special_param_construction(struct spdk_iscsi_conn *conn, 541 struct iscsi_param *param, 542 bool FirstBurstLength_flag, char *data, 543 int alloc_len, int total) 544 { 545 int len; 546 struct iscsi_param *param_first; 547 struct iscsi_param *param_max; 548 uint32_t FirstBurstLength; 549 uint32_t MaxBurstLength; 550 char *val; 551 552 val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 553 if (!val) { 554 SPDK_ERRLOG("malloc() failed for temporary buffer\n"); 555 return -ENOMEM; 556 } 557 558 if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) { 559 /* 560 * MaxRecvDataSegmentLength is sent by both 561 * initiator and target, but is declarative - meaning 562 * each direction can have different values. 563 * So when MaxRecvDataSegmentLength is found in the 564 * the parameter set sent from the initiator, add SPDK 565 * iscsi target's MaxRecvDataSegmentLength value to 566 * the returned parameter list. 567 */ 568 if (alloc_len - total < 1) { 569 SPDK_ERRLOG("data space small %d\n", alloc_len); 570 free(val); 571 return -1; 572 } 573 574 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 575 "returning MaxRecvDataSegmentLength=%d\n", 576 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 577 len = snprintf((char *)data + total, alloc_len - total, 578 "MaxRecvDataSegmentLength=%d", 579 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 580 total += len + 1; 581 } 582 583 if (strcasecmp(param->key, "MaxBurstLength") == 0 && 584 !FirstBurstLength_flag) { 585 if (alloc_len - total < 1) { 586 SPDK_ERRLOG("data space small %d\n", alloc_len); 587 free(val); 588 return -1; 589 } 590 591 param_first = spdk_iscsi_param_find(conn->sess->params, 592 "FirstBurstLength"); 593 if (param_first != NULL) { 594 FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10); 595 } else { 596 FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 597 } 598 param_max = spdk_iscsi_param_find(conn->sess->params, 599 "MaxBurstLength"); 600 if (param_max != NULL) { 601 MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10); 602 } else { 603 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 604 } 605 606 if (FirstBurstLength > MaxBurstLength) { 607 FirstBurstLength = MaxBurstLength; 608 if (param_first != NULL) { 609 free(param_first->val); 610 snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 611 FirstBurstLength); 612 param_first->val = xstrdup(val); 613 } 614 } 615 len = snprintf((char *)data + total, alloc_len - total, 616 "FirstBurstLength=%d", FirstBurstLength); 617 total += len + 1; 618 } 619 620 free(val); 621 return total; 622 623 } 624 625 /** 626 * spdk_iscsi_construct_data_from_param: 627 * To construct the data which will be returned to the initiator 628 * return: length of the negotiated data, -1 indicates error; 629 */ 630 static int 631 spdk_iscsi_construct_data_from_param(struct iscsi_param *param, char *new_val, 632 char *data, int alloc_len, int total) 633 { 634 int len; 635 636 if (param->type != ISPT_DECLARATIVE && 637 param->type != ISPT_NUMERICAL_DECLARATIVE) { 638 if (alloc_len - total < 1) { 639 SPDK_ERRLOG("data space small %d\n", alloc_len); 640 return -1; 641 } 642 643 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "negotiated %s=%s\n", 644 param->key, new_val); 645 len = snprintf((char *)data + total, alloc_len - total, "%s=%s", 646 param->key, new_val); 647 total += len + 1; 648 } 649 return total; 650 } 651 652 /** 653 * To negotiate param with 654 * type = ISPT_LIST 655 * return: the negotiated value of the key 656 */ 657 static char *spdk_iscsi_negotiate_param_list(int *add_param_value, 658 struct iscsi_param *param, 659 char *valid_list, char *in_val, 660 char *cur_val) 661 { 662 char *val_start, *val_end; 663 char *in_start, *in_end; 664 int flag = 0; 665 666 if (add_param_value == NULL) { 667 return NULL; 668 } 669 670 in_start = in_val; 671 do { 672 if ((in_end = strchr(in_start, (int)',')) != NULL) { 673 *in_end = '\0'; 674 } 675 val_start = valid_list; 676 do { 677 if ((val_end = strchr(val_start, (int)',')) != NULL) { 678 *val_end = '\0'; 679 } 680 if (strcasecmp(in_start, val_start) == 0) { 681 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "match %s\n", 682 val_start); 683 flag = 1; 684 break; 685 } 686 if (val_end) { 687 *val_end = ','; 688 val_start = val_end + 1; 689 } 690 } while (val_end); 691 if (flag) { 692 break; 693 } 694 if (in_end) { 695 *in_end = ','; 696 in_start = in_end + 1; 697 } 698 } while (in_end); 699 700 return flag ? val_start : NULL; 701 } 702 703 /** 704 * To negotiate param with 705 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE 706 * return: the negotiated value of the key 707 */ 708 static char *spdk_iscsi_negotiate_param_numerical(int *add_param_value, 709 struct iscsi_param *param, 710 char *valid_list, char *in_val, 711 char *cur_val) 712 { 713 char *valid_next; 714 char *new_val = NULL; 715 char *min_val, *max_val; 716 int val_i, cur_val_i; 717 int min_i, max_i; 718 719 if (add_param_value == NULL) { 720 return NULL; 721 } 722 723 val_i = (int)strtol(param->val, NULL, 10); 724 /* check whether the key is FirstBurstLength, if that we use in_val */ 725 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 726 val_i = (int)strtol(in_val, NULL, 10); 727 } 728 729 cur_val_i = (int)strtol(cur_val, NULL, 10); 730 valid_next = valid_list; 731 min_val = spdk_strsepq(&valid_next, ","); 732 max_val = spdk_strsepq(&valid_next, ","); 733 min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0; 734 max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0; 735 if (val_i < min_i || val_i > max_i) { 736 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "key %.64s reject\n", param->key); 737 new_val = NULL; 738 } else { 739 switch (param->type) { 740 case ISPT_NUMERICAL_MIN: 741 if (val_i > cur_val_i) { 742 val_i = cur_val_i; 743 } 744 break; 745 case ISPT_NUMERICAL_MAX: 746 if (val_i < cur_val_i) { 747 val_i = cur_val_i; 748 } 749 break; 750 default: 751 break; 752 } 753 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); 754 new_val = in_val; 755 } 756 757 return new_val; 758 } 759 760 /** 761 * To negotiate param with 762 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND 763 * return: the negotiated value of the key 764 */ 765 static char *spdk_iscsi_negotiate_param_boolean(int *add_param_value, 766 struct iscsi_param *param, 767 char *in_val, char *cur_val, 768 const char *value) 769 { 770 char *new_val = NULL; 771 772 if (add_param_value == NULL) { 773 return NULL; 774 } 775 776 /* Make sure the val is Yes or No */ 777 if (!((strcasecmp(in_val, "Yes") == 0) || 778 (strcasecmp(in_val, "No") == 0))) { 779 /* unknown value */ 780 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject"); 781 new_val = in_val; 782 *add_param_value = 1; 783 return new_val; 784 } 785 786 if (strcasecmp(cur_val, value) == 0) { 787 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value); 788 new_val = in_val; 789 } else { 790 new_val = param->val; 791 } 792 793 return new_val; 794 } 795 796 /** 797 * The entry function to handle each type of the param 798 * return value: the new negotiated value 799 */ 800 static char * 801 spdk_iscsi_negotiate_param_all(int *add_param_value, struct iscsi_param *param, 802 char *valid_list, char *in_val, char *cur_val) 803 { 804 char *new_val; 805 switch (param->type) { 806 case ISPT_LIST: 807 new_val = spdk_iscsi_negotiate_param_list(add_param_value, 808 param, 809 valid_list, 810 in_val, 811 cur_val); 812 break; 813 814 case ISPT_NUMERICAL_MIN: 815 case ISPT_NUMERICAL_MAX: 816 case ISPT_NUMERICAL_DECLARATIVE: 817 new_val = spdk_iscsi_negotiate_param_numerical(add_param_value, 818 param, 819 valid_list, 820 in_val, 821 cur_val); 822 break; 823 824 case ISPT_BOOLEAN_OR: 825 new_val = spdk_iscsi_negotiate_param_boolean(add_param_value, 826 param, 827 in_val, 828 cur_val, 829 "Yes"); 830 break; 831 case ISPT_BOOLEAN_AND: 832 new_val = spdk_iscsi_negotiate_param_boolean(add_param_value, 833 param, 834 in_val, 835 cur_val, 836 "No"); 837 break; 838 839 default: 840 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 841 new_val = in_val; 842 break; 843 } 844 845 return new_val; 846 } 847 848 /** 849 * This function is used to judge whether the param is in session's params or 850 * connection's params 851 */ 852 static int 853 spdk_iscsi_negotiate_param_init(struct spdk_iscsi_conn *conn, 854 struct iscsi_param **cur_param_p, 855 struct iscsi_param **params_dst_p, 856 struct iscsi_param *param) 857 { 858 int index; 859 860 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 861 if (*cur_param_p == NULL) { 862 *params_dst_p = conn->sess->params; 863 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 864 if (*cur_param_p == NULL) { 865 if ((strncasecmp(param->key, "X-", 2) == 0) || 866 (strncasecmp(param->key, "X#", 2) == 0)) { 867 /* Extension Key */ 868 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 869 "extension key %.64s\n", 870 param->key); 871 } else { 872 SPDK_ERRLOG("unknown key %.64s\n", param->key); 873 } 874 return 1; 875 } else { 876 index = (*cur_param_p)->state_index; 877 if (conn->sess_param_state_negotiated[index] && 878 !spdk_iscsi_find_key_in_array(param->key, 879 target_declarative_params)) { 880 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 881 } 882 conn->sess_param_state_negotiated[index] = true; 883 } 884 } else { 885 index = (*cur_param_p)->state_index; 886 if (conn->conn_param_state_negotiated[index] && 887 !spdk_iscsi_find_key_in_array(param->key, 888 multi_negot_conn_params)) { 889 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 890 } 891 conn->conn_param_state_negotiated[index] = true; 892 } 893 894 return 0; 895 } 896 897 int 898 spdk_iscsi_negotiate_params(struct spdk_iscsi_conn *conn, 899 struct iscsi_param **params, uint8_t *data, int alloc_len, 900 int data_len) 901 { 902 struct iscsi_param *param; 903 struct iscsi_param *cur_param; 904 char *valid_list, *in_val; 905 char *cur_val; 906 char *new_val; 907 int discovery; 908 int total; 909 int rc; 910 uint32_t FirstBurstLength; 911 uint32_t MaxBurstLength; 912 bool FirstBurstLength_flag = false; 913 int type; 914 915 total = data_len; 916 if (data_len < 0) { 917 assert(false); 918 return -EINVAL; 919 } 920 if (alloc_len < 1) { 921 return 0; 922 } 923 if (total > alloc_len) { 924 total = alloc_len; 925 data[total - 1] = '\0'; 926 return total; 927 } 928 929 if (*params == NULL) { 930 /* no input */ 931 return total; 932 } 933 934 /* discovery? */ 935 discovery = 0; 936 cur_param = spdk_iscsi_param_find(*params, "SessionType"); 937 if (cur_param == NULL) { 938 cur_param = spdk_iscsi_param_find(conn->sess->params, "SessionType"); 939 if (cur_param == NULL) { 940 /* no session type */ 941 } else { 942 if (strcasecmp(cur_param->val, "Discovery") == 0) { 943 discovery = 1; 944 } 945 } 946 } else { 947 if (strcasecmp(cur_param->val, "Discovery") == 0) { 948 discovery = 1; 949 } 950 } 951 952 /* for temporary store */ 953 valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 954 if (!valid_list) { 955 SPDK_ERRLOG("malloc() failed for valid_list\n"); 956 return -ENOMEM; 957 } 958 959 in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 960 if (!in_val) { 961 SPDK_ERRLOG("malloc() failed for in_val\n"); 962 free(valid_list); 963 return -ENOMEM; 964 } 965 966 cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 967 if (!cur_val) { 968 SPDK_ERRLOG("malloc() failed for cur_val\n"); 969 free(valid_list); 970 free(in_val); 971 return -ENOMEM; 972 } 973 974 /* To adjust the location of FirstBurstLength location and put it to 975 * the end, then we can always firstly determine the MaxBurstLength 976 */ 977 param = spdk_iscsi_param_find(*params, "MaxBurstLength"); 978 if (param != NULL) { 979 param = spdk_iscsi_param_find(*params, "FirstBurstLength"); 980 981 /* check the existence of FirstBurstLength */ 982 if (param != NULL) { 983 FirstBurstLength_flag = true; 984 if (param->next != NULL) { 985 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 986 type = param->type; 987 spdk_iscsi_param_add(params, "FirstBurstLength", 988 in_val, NULL, type); 989 } 990 } 991 } 992 993 for (param = *params; param != NULL; param = param->next) { 994 struct iscsi_param *params_dst = conn->params; 995 int add_param_value = 0; 996 new_val = NULL; 997 param->type = ISPT_INVALID; 998 999 /* sendtargets is special */ 1000 if (strcasecmp(param->key, "SendTargets") == 0) { 1001 continue; 1002 } 1003 /* CHAP keys */ 1004 if (spdk_iscsi_find_key_in_array(param->key, chap_type)) { 1005 continue; 1006 } 1007 1008 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ 1009 if (discovery && 1010 spdk_iscsi_find_key_in_array(param->key, 1011 discovery_ignored_param)) { 1012 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant"); 1013 new_val = in_val; 1014 add_param_value = 1; 1015 } else { 1016 rc = spdk_iscsi_negotiate_param_init(conn, 1017 &cur_param, 1018 ¶ms_dst, 1019 param); 1020 if (rc < 0) { 1021 free(valid_list); 1022 free(in_val); 1023 free(cur_val); 1024 return rc; 1025 } else if (rc > 0) { 1026 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood"); 1027 new_val = in_val; 1028 add_param_value = 1; 1029 } else { 1030 snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list); 1031 snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val); 1032 param->type = cur_param->type; 1033 } 1034 } 1035 1036 if (param->type > 0) { 1037 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1038 1039 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */ 1040 if (strcasecmp(in_val, "NotUnderstood") == 0) { 1041 free(in_val); 1042 free(valid_list); 1043 free(cur_val); 1044 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER; 1045 } 1046 1047 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 1048 FirstBurstLength = (uint32_t)strtol(param->val, NULL, 1049 10); 1050 new_val = spdk_iscsi_param_get_val(conn->sess->params, 1051 "MaxBurstLength"); 1052 if (new_val != NULL) { 1053 MaxBurstLength = (uint32_t) strtol(new_val, NULL, 1054 10); 1055 } else { 1056 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 1057 } 1058 if (FirstBurstLength < SPDK_ISCSI_MAX_FIRST_BURST_LENGTH && 1059 FirstBurstLength > MaxBurstLength) { 1060 FirstBurstLength = MaxBurstLength; 1061 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 1062 FirstBurstLength); 1063 } 1064 } 1065 1066 /* prevent target's declarative params from being changed by initiator */ 1067 if (spdk_iscsi_find_key_in_array(param->key, target_declarative_params)) { 1068 add_param_value = 1; 1069 } 1070 1071 new_val = spdk_iscsi_negotiate_param_all(&add_param_value, 1072 param, 1073 valid_list, 1074 in_val, 1075 cur_val); 1076 } 1077 1078 /* check the negotiated value of the key */ 1079 if (new_val != NULL) { 1080 /* add_param_value = 0 means updating the value of 1081 * existed key in the connection's parameters 1082 */ 1083 if (add_param_value == 0) { 1084 spdk_iscsi_param_set(params_dst, param->key, new_val); 1085 } 1086 total = spdk_iscsi_construct_data_from_param(param, 1087 new_val, 1088 data, 1089 alloc_len, 1090 total); 1091 if (total < 0) { 1092 goto final_return; 1093 } 1094 1095 total = spdk_iscsi_special_param_construction(conn, 1096 param, 1097 FirstBurstLength_flag, 1098 data, 1099 alloc_len, 1100 total); 1101 if (total < 0) { 1102 goto final_return; 1103 } 1104 } else { 1105 total = -1; 1106 break; 1107 } 1108 } 1109 1110 final_return: 1111 free(valid_list); 1112 free(in_val); 1113 free(cur_val); 1114 1115 return total; 1116 } 1117 1118 int 1119 spdk_iscsi_copy_param2var(struct spdk_iscsi_conn *conn) 1120 { 1121 const char *val; 1122 1123 val = spdk_iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength"); 1124 if (val == NULL) { 1125 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n"); 1126 return -1; 1127 } 1128 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 1129 "copy MaxRecvDataSegmentLength=%s\n", val); 1130 conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); 1131 if (conn->MaxRecvDataSegmentLength > SPDK_BDEV_LARGE_BUF_MAX_SIZE) { 1132 conn->MaxRecvDataSegmentLength = SPDK_BDEV_LARGE_BUF_MAX_SIZE; 1133 } 1134 1135 val = spdk_iscsi_param_get_val(conn->params, "HeaderDigest"); 1136 if (val == NULL) { 1137 SPDK_ERRLOG("Getval HeaderDigest failed\n"); 1138 return -1; 1139 } 1140 if (strcasecmp(val, "CRC32C") == 0) { 1141 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=1\n"); 1142 conn->header_digest = 1; 1143 } else { 1144 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=0\n"); 1145 conn->header_digest = 0; 1146 } 1147 val = spdk_iscsi_param_get_val(conn->params, "DataDigest"); 1148 if (val == NULL) { 1149 SPDK_ERRLOG("Getval DataDigest failed\n"); 1150 return -1; 1151 } 1152 if (strcasecmp(val, "CRC32C") == 0) { 1153 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=1\n"); 1154 conn->data_digest = 1; 1155 } else { 1156 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=0\n"); 1157 conn->data_digest = 0; 1158 } 1159 1160 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxConnections"); 1161 if (val == NULL) { 1162 SPDK_ERRLOG("Getval MaxConnections failed\n"); 1163 return -1; 1164 } 1165 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxConnections=%s\n", val); 1166 conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10); 1167 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T"); 1168 if (val == NULL) { 1169 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n"); 1170 return -1; 1171 } 1172 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxOutstandingR2T=%s\n", val); 1173 conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10); 1174 val = spdk_iscsi_param_get_val(conn->sess->params, "FirstBurstLength"); 1175 if (val == NULL) { 1176 SPDK_ERRLOG("Getval FirstBurstLength failed\n"); 1177 return -1; 1178 } 1179 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy FirstBurstLength=%s\n", val); 1180 conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10); 1181 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxBurstLength"); 1182 if (val == NULL) { 1183 SPDK_ERRLOG("Getval MaxBurstLength failed\n"); 1184 return -1; 1185 } 1186 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxBurstLength=%s\n", val); 1187 conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10); 1188 val = spdk_iscsi_param_get_val(conn->sess->params, "InitialR2T"); 1189 if (val == NULL) { 1190 SPDK_ERRLOG("Getval InitialR2T failed\n"); 1191 return -1; 1192 } 1193 if (strcasecmp(val, "Yes") == 0) { 1194 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=1\n"); 1195 conn->sess->InitialR2T = true; 1196 } else { 1197 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=0\n"); 1198 conn->sess->InitialR2T = false; 1199 } 1200 val = spdk_iscsi_param_get_val(conn->sess->params, "ImmediateData"); 1201 if (val == NULL) { 1202 SPDK_ERRLOG("Getval ImmediateData failed\n"); 1203 return -1; 1204 } 1205 if (strcasecmp(val, "Yes") == 0) { 1206 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=1\n"); 1207 conn->sess->ImmediateData = true; 1208 } else { 1209 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=0\n"); 1210 conn->sess->ImmediateData = false; 1211 } 1212 return 0; 1213 } 1214