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