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