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 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 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 = 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 = 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 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 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 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 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 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 * 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 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 * 658 iscsi_negotiate_param_list(int *add_param_value, 659 struct iscsi_param *param, 660 char *valid_list, char *in_val, 661 char *cur_val) 662 { 663 char *val_start, *val_end; 664 char *in_start, *in_end; 665 int flag = 0; 666 667 if (add_param_value == NULL) { 668 return NULL; 669 } 670 671 in_start = in_val; 672 do { 673 if ((in_end = strchr(in_start, (int)',')) != NULL) { 674 *in_end = '\0'; 675 } 676 val_start = valid_list; 677 do { 678 if ((val_end = strchr(val_start, (int)',')) != NULL) { 679 *val_end = '\0'; 680 } 681 if (strcasecmp(in_start, val_start) == 0) { 682 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "match %s\n", 683 val_start); 684 flag = 1; 685 break; 686 } 687 if (val_end) { 688 *val_end = ','; 689 val_start = val_end + 1; 690 } 691 } while (val_end); 692 if (flag) { 693 break; 694 } 695 if (in_end) { 696 *in_end = ','; 697 in_start = in_end + 1; 698 } 699 } while (in_end); 700 701 return flag ? val_start : NULL; 702 } 703 704 /** 705 * To negotiate param with 706 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE 707 * return: the negotiated value of the key 708 */ 709 static char * 710 iscsi_negotiate_param_numerical(int *add_param_value, 711 struct iscsi_param *param, 712 char *valid_list, char *in_val, 713 char *cur_val) 714 { 715 char *valid_next; 716 char *new_val = NULL; 717 char *min_val, *max_val; 718 int val_i, cur_val_i; 719 int min_i, max_i; 720 721 if (add_param_value == NULL) { 722 return NULL; 723 } 724 725 val_i = (int)strtol(param->val, NULL, 10); 726 /* check whether the key is FirstBurstLength, if that we use in_val */ 727 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 728 val_i = (int)strtol(in_val, NULL, 10); 729 } 730 731 cur_val_i = (int)strtol(cur_val, NULL, 10); 732 valid_next = valid_list; 733 min_val = spdk_strsepq(&valid_next, ","); 734 max_val = spdk_strsepq(&valid_next, ","); 735 min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0; 736 max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0; 737 if (val_i < min_i || val_i > max_i) { 738 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "key %.64s reject\n", param->key); 739 new_val = NULL; 740 } else { 741 switch (param->type) { 742 case ISPT_NUMERICAL_MIN: 743 if (val_i > cur_val_i) { 744 val_i = cur_val_i; 745 } 746 break; 747 case ISPT_NUMERICAL_MAX: 748 if (val_i < cur_val_i) { 749 val_i = cur_val_i; 750 } 751 break; 752 default: 753 break; 754 } 755 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); 756 new_val = in_val; 757 } 758 759 return new_val; 760 } 761 762 /** 763 * To negotiate param with 764 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND 765 * return: the negotiated value of the key 766 */ 767 static char * 768 iscsi_negotiate_param_boolean(int *add_param_value, 769 struct iscsi_param *param, 770 char *in_val, char *cur_val, 771 const char *value) 772 { 773 char *new_val = NULL; 774 775 if (add_param_value == NULL) { 776 return NULL; 777 } 778 779 /* Make sure the val is Yes or No */ 780 if (!((strcasecmp(in_val, "Yes") == 0) || 781 (strcasecmp(in_val, "No") == 0))) { 782 /* unknown value */ 783 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject"); 784 new_val = in_val; 785 *add_param_value = 1; 786 return new_val; 787 } 788 789 if (strcasecmp(cur_val, value) == 0) { 790 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value); 791 new_val = in_val; 792 } else { 793 new_val = param->val; 794 } 795 796 return new_val; 797 } 798 799 /** 800 * The entry function to handle each type of the param 801 * return value: the new negotiated value 802 */ 803 static char * 804 iscsi_negotiate_param_all(int *add_param_value, struct iscsi_param *param, 805 char *valid_list, char *in_val, char *cur_val) 806 { 807 char *new_val; 808 switch (param->type) { 809 case ISPT_LIST: 810 new_val = iscsi_negotiate_param_list(add_param_value, 811 param, 812 valid_list, 813 in_val, 814 cur_val); 815 break; 816 817 case ISPT_NUMERICAL_MIN: 818 case ISPT_NUMERICAL_MAX: 819 case ISPT_NUMERICAL_DECLARATIVE: 820 new_val = iscsi_negotiate_param_numerical(add_param_value, 821 param, 822 valid_list, 823 in_val, 824 cur_val); 825 break; 826 827 case ISPT_BOOLEAN_OR: 828 new_val = iscsi_negotiate_param_boolean(add_param_value, 829 param, 830 in_val, 831 cur_val, 832 "Yes"); 833 break; 834 case ISPT_BOOLEAN_AND: 835 new_val = iscsi_negotiate_param_boolean(add_param_value, 836 param, 837 in_val, 838 cur_val, 839 "No"); 840 break; 841 842 default: 843 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 844 new_val = in_val; 845 break; 846 } 847 848 return new_val; 849 } 850 851 /** 852 * This function is used to judge whether the param is in session's params or 853 * connection's params 854 */ 855 static int 856 iscsi_negotiate_param_init(struct spdk_iscsi_conn *conn, 857 struct iscsi_param **cur_param_p, 858 struct iscsi_param **params_dst_p, 859 struct iscsi_param *param) 860 { 861 int index; 862 863 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 864 if (*cur_param_p == NULL) { 865 *params_dst_p = conn->sess->params; 866 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 867 if (*cur_param_p == NULL) { 868 if ((strncasecmp(param->key, "X-", 2) == 0) || 869 (strncasecmp(param->key, "X#", 2) == 0)) { 870 /* Extension Key */ 871 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 872 "extension key %.64s\n", 873 param->key); 874 } else { 875 SPDK_ERRLOG("unknown key %.64s\n", param->key); 876 } 877 return 1; 878 } else { 879 index = (*cur_param_p)->state_index; 880 if (conn->sess_param_state_negotiated[index] && 881 !iscsi_find_key_in_array(param->key, 882 target_declarative_params)) { 883 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 884 } 885 conn->sess_param_state_negotiated[index] = true; 886 } 887 } else { 888 index = (*cur_param_p)->state_index; 889 if (conn->conn_param_state_negotiated[index] && 890 !iscsi_find_key_in_array(param->key, 891 multi_negot_conn_params)) { 892 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 893 } 894 conn->conn_param_state_negotiated[index] = true; 895 } 896 897 return 0; 898 } 899 900 int 901 spdk_iscsi_negotiate_params(struct spdk_iscsi_conn *conn, 902 struct iscsi_param **params, uint8_t *data, int alloc_len, 903 int data_len) 904 { 905 struct iscsi_param *param; 906 struct iscsi_param *cur_param; 907 char *valid_list, *in_val; 908 char *cur_val; 909 char *new_val; 910 int discovery; 911 int total; 912 int rc; 913 uint32_t FirstBurstLength; 914 uint32_t MaxBurstLength; 915 bool FirstBurstLength_flag = false; 916 int type; 917 918 total = data_len; 919 if (data_len < 0) { 920 assert(false); 921 return -EINVAL; 922 } 923 if (alloc_len < 1) { 924 return 0; 925 } 926 if (total > alloc_len) { 927 total = alloc_len; 928 data[total - 1] = '\0'; 929 return total; 930 } 931 932 if (*params == NULL) { 933 /* no input */ 934 return total; 935 } 936 937 /* discovery? */ 938 discovery = 0; 939 cur_param = spdk_iscsi_param_find(*params, "SessionType"); 940 if (cur_param == NULL) { 941 cur_param = spdk_iscsi_param_find(conn->sess->params, "SessionType"); 942 if (cur_param == NULL) { 943 /* no session type */ 944 } else { 945 if (strcasecmp(cur_param->val, "Discovery") == 0) { 946 discovery = 1; 947 } 948 } 949 } else { 950 if (strcasecmp(cur_param->val, "Discovery") == 0) { 951 discovery = 1; 952 } 953 } 954 955 /* for temporary store */ 956 valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 957 if (!valid_list) { 958 SPDK_ERRLOG("malloc() failed for valid_list\n"); 959 return -ENOMEM; 960 } 961 962 in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 963 if (!in_val) { 964 SPDK_ERRLOG("malloc() failed for in_val\n"); 965 free(valid_list); 966 return -ENOMEM; 967 } 968 969 cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 970 if (!cur_val) { 971 SPDK_ERRLOG("malloc() failed for cur_val\n"); 972 free(valid_list); 973 free(in_val); 974 return -ENOMEM; 975 } 976 977 /* To adjust the location of FirstBurstLength location and put it to 978 * the end, then we can always firstly determine the MaxBurstLength 979 */ 980 param = spdk_iscsi_param_find(*params, "MaxBurstLength"); 981 if (param != NULL) { 982 param = spdk_iscsi_param_find(*params, "FirstBurstLength"); 983 984 /* check the existence of FirstBurstLength */ 985 if (param != NULL) { 986 FirstBurstLength_flag = true; 987 if (param->next != NULL) { 988 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 989 type = param->type; 990 spdk_iscsi_param_add(params, "FirstBurstLength", 991 in_val, NULL, type); 992 } 993 } 994 } 995 996 for (param = *params; param != NULL; param = param->next) { 997 struct iscsi_param *params_dst = conn->params; 998 int add_param_value = 0; 999 new_val = NULL; 1000 param->type = ISPT_INVALID; 1001 1002 /* sendtargets is special */ 1003 if (strcasecmp(param->key, "SendTargets") == 0) { 1004 continue; 1005 } 1006 /* CHAP keys */ 1007 if (iscsi_find_key_in_array(param->key, chap_type)) { 1008 continue; 1009 } 1010 1011 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ 1012 if (discovery && 1013 iscsi_find_key_in_array(param->key, discovery_ignored_param)) { 1014 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant"); 1015 new_val = in_val; 1016 add_param_value = 1; 1017 } else { 1018 rc = iscsi_negotiate_param_init(conn, 1019 &cur_param, 1020 ¶ms_dst, 1021 param); 1022 if (rc < 0) { 1023 free(valid_list); 1024 free(in_val); 1025 free(cur_val); 1026 return rc; 1027 } else if (rc > 0) { 1028 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood"); 1029 new_val = in_val; 1030 add_param_value = 1; 1031 } else { 1032 snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list); 1033 snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val); 1034 param->type = cur_param->type; 1035 } 1036 } 1037 1038 if (param->type > 0) { 1039 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1040 1041 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */ 1042 if (strcasecmp(in_val, "NotUnderstood") == 0) { 1043 free(in_val); 1044 free(valid_list); 1045 free(cur_val); 1046 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER; 1047 } 1048 1049 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 1050 FirstBurstLength = (uint32_t)strtol(param->val, NULL, 1051 10); 1052 new_val = spdk_iscsi_param_get_val(conn->sess->params, 1053 "MaxBurstLength"); 1054 if (new_val != NULL) { 1055 MaxBurstLength = (uint32_t) strtol(new_val, NULL, 1056 10); 1057 } else { 1058 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 1059 } 1060 if (FirstBurstLength < SPDK_ISCSI_MAX_FIRST_BURST_LENGTH && 1061 FirstBurstLength > MaxBurstLength) { 1062 FirstBurstLength = MaxBurstLength; 1063 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 1064 FirstBurstLength); 1065 } 1066 } 1067 1068 /* prevent target's declarative params from being changed by initiator */ 1069 if (iscsi_find_key_in_array(param->key, target_declarative_params)) { 1070 add_param_value = 1; 1071 } 1072 1073 new_val = iscsi_negotiate_param_all(&add_param_value, 1074 param, 1075 valid_list, 1076 in_val, 1077 cur_val); 1078 } 1079 1080 /* check the negotiated value of the key */ 1081 if (new_val != NULL) { 1082 /* add_param_value = 0 means updating the value of 1083 * existed key in the connection's parameters 1084 */ 1085 if (add_param_value == 0) { 1086 spdk_iscsi_param_set(params_dst, param->key, new_val); 1087 } 1088 total = iscsi_construct_data_from_param(param, 1089 new_val, 1090 data, 1091 alloc_len, 1092 total); 1093 if (total < 0) { 1094 goto final_return; 1095 } 1096 1097 total = iscsi_special_param_construction(conn, 1098 param, 1099 FirstBurstLength_flag, 1100 data, 1101 alloc_len, 1102 total); 1103 if (total < 0) { 1104 goto final_return; 1105 } 1106 } else { 1107 total = -1; 1108 break; 1109 } 1110 } 1111 1112 final_return: 1113 free(valid_list); 1114 free(in_val); 1115 free(cur_val); 1116 1117 return total; 1118 } 1119 1120 int 1121 spdk_iscsi_copy_param2var(struct spdk_iscsi_conn *conn) 1122 { 1123 const char *val; 1124 1125 val = spdk_iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength"); 1126 if (val == NULL) { 1127 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n"); 1128 return -1; 1129 } 1130 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 1131 "copy MaxRecvDataSegmentLength=%s\n", val); 1132 conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); 1133 if (conn->MaxRecvDataSegmentLength > SPDK_BDEV_LARGE_BUF_MAX_SIZE) { 1134 conn->MaxRecvDataSegmentLength = SPDK_BDEV_LARGE_BUF_MAX_SIZE; 1135 } 1136 1137 val = spdk_iscsi_param_get_val(conn->params, "HeaderDigest"); 1138 if (val == NULL) { 1139 SPDK_ERRLOG("Getval HeaderDigest failed\n"); 1140 return -1; 1141 } 1142 if (strcasecmp(val, "CRC32C") == 0) { 1143 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=1\n"); 1144 conn->header_digest = 1; 1145 } else { 1146 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=0\n"); 1147 conn->header_digest = 0; 1148 } 1149 val = spdk_iscsi_param_get_val(conn->params, "DataDigest"); 1150 if (val == NULL) { 1151 SPDK_ERRLOG("Getval DataDigest failed\n"); 1152 return -1; 1153 } 1154 if (strcasecmp(val, "CRC32C") == 0) { 1155 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=1\n"); 1156 conn->data_digest = 1; 1157 } else { 1158 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=0\n"); 1159 conn->data_digest = 0; 1160 } 1161 1162 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxConnections"); 1163 if (val == NULL) { 1164 SPDK_ERRLOG("Getval MaxConnections failed\n"); 1165 return -1; 1166 } 1167 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxConnections=%s\n", val); 1168 conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10); 1169 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T"); 1170 if (val == NULL) { 1171 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n"); 1172 return -1; 1173 } 1174 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxOutstandingR2T=%s\n", val); 1175 conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10); 1176 val = spdk_iscsi_param_get_val(conn->sess->params, "FirstBurstLength"); 1177 if (val == NULL) { 1178 SPDK_ERRLOG("Getval FirstBurstLength failed\n"); 1179 return -1; 1180 } 1181 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy FirstBurstLength=%s\n", val); 1182 conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10); 1183 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxBurstLength"); 1184 if (val == NULL) { 1185 SPDK_ERRLOG("Getval MaxBurstLength failed\n"); 1186 return -1; 1187 } 1188 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxBurstLength=%s\n", val); 1189 conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10); 1190 val = spdk_iscsi_param_get_val(conn->sess->params, "InitialR2T"); 1191 if (val == NULL) { 1192 SPDK_ERRLOG("Getval InitialR2T failed\n"); 1193 return -1; 1194 } 1195 if (strcasecmp(val, "Yes") == 0) { 1196 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=1\n"); 1197 conn->sess->InitialR2T = true; 1198 } else { 1199 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=0\n"); 1200 conn->sess->InitialR2T = false; 1201 } 1202 val = spdk_iscsi_param_get_val(conn->sess->params, "ImmediateData"); 1203 if (val == NULL) { 1204 SPDK_ERRLOG("Getval ImmediateData failed\n"); 1205 return -1; 1206 } 1207 if (strcasecmp(val, "Yes") == 0) { 1208 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=1\n"); 1209 conn->sess->ImmediateData = true; 1210 } else { 1211 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=0\n"); 1212 conn->sess->ImmediateData = false; 1213 } 1214 return 0; 1215 } 1216