1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>. 5 * Copyright (c) Intel Corporation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * * Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * * Neither the name of Intel Corporation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "spdk/stdinc.h" 36 37 #include "spdk/string.h" 38 #include "iscsi/iscsi.h" 39 #include "iscsi/param.h" 40 #include "iscsi/conn.h" 41 #include "spdk/string.h" 42 43 #include "spdk_internal/log.h" 44 45 #define MAX_TMPBUF 1024 46 47 /* whose value may be bigger than 255 */ 48 static const char *non_simple_value_params[] = { 49 "CHAP_C", 50 "CHAP_R", 51 NULL, 52 }; 53 54 void 55 spdk_iscsi_param_free(struct iscsi_param *params) 56 { 57 struct iscsi_param *param, *next_param; 58 59 if (params == NULL) { 60 return; 61 } 62 for (param = params; param != NULL; param = next_param) { 63 next_param = param->next; 64 if (param->list) { 65 free(param->list); 66 } 67 free(param->val); 68 free(param->key); 69 free(param); 70 } 71 } 72 73 static int 74 spdk_iscsi_find_key_in_array(const char *key, const char *array[]) 75 { 76 int i; 77 78 for (i = 0; array[i] != NULL; i++) { 79 if (strcasecmp(key, array[i]) == 0) { 80 return 1; 81 } 82 } 83 return 0; 84 } 85 86 struct iscsi_param * 87 spdk_iscsi_param_find(struct iscsi_param *params, const char *key) 88 { 89 struct iscsi_param *param; 90 91 if (params == NULL || key == NULL) { 92 return NULL; 93 } 94 for (param = params; param != NULL; param = param->next) { 95 if (param->key != NULL && param->key[0] == key[0] 96 && strcasecmp(param->key, key) == 0) { 97 return param; 98 } 99 } 100 return NULL; 101 } 102 103 int 104 spdk_iscsi_param_del(struct iscsi_param **params, const char *key) 105 { 106 struct iscsi_param *param, *prev_param = NULL; 107 108 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "del %s\n", key); 109 if (params == NULL || key == NULL) { 110 return 0; 111 } 112 for (param = *params; param != NULL; param = param->next) { 113 if (param->key != NULL && param->key[0] == key[0] 114 && strcasecmp(param->key, key) == 0) { 115 if (prev_param != NULL) { 116 prev_param->next = param->next; 117 } else { 118 *params = param->next; 119 } 120 param->next = NULL; 121 spdk_iscsi_param_free(param); 122 return 0; 123 } 124 prev_param = param; 125 } 126 return -1; 127 } 128 129 int 130 spdk_iscsi_param_add(struct iscsi_param **params, const char *key, 131 const char *val, const char *list, int type) 132 { 133 struct iscsi_param *param, *last_param; 134 135 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "add %s=%s, list=[%s], type=%d\n", 136 key, val, list, type); 137 if (key == NULL) { 138 return -1; 139 } 140 141 param = spdk_iscsi_param_find(*params, key); 142 if (param != NULL) { 143 spdk_iscsi_param_del(params, key); 144 } 145 146 param = calloc(1, sizeof(*param)); 147 if (!param) { 148 SPDK_ERRLOG("calloc() failed for parameter\n"); 149 return -ENOMEM; 150 } 151 152 param->next = NULL; 153 param->key = xstrdup(key); 154 param->val = xstrdup(val); 155 param->list = xstrdup(list); 156 param->type = type; 157 158 last_param = *params; 159 if (last_param != NULL) { 160 while (last_param->next != NULL) { 161 last_param = last_param->next; 162 } 163 last_param->next = param; 164 } else { 165 *params = param; 166 } 167 168 return 0; 169 } 170 171 int 172 spdk_iscsi_param_set(struct iscsi_param *params, const char *key, 173 const char *val) 174 { 175 struct iscsi_param *param; 176 177 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set %s=%s\n", key, val); 178 param = spdk_iscsi_param_find(params, key); 179 if (param == NULL) { 180 SPDK_ERRLOG("no key %s\n", key); 181 return -1; 182 } 183 184 free(param->val); 185 186 param->val = xstrdup(val); 187 188 return 0; 189 } 190 191 int 192 spdk_iscsi_param_set_int(struct iscsi_param *params, const char *key, uint32_t val) 193 { 194 char buf[MAX_TMPBUF]; 195 struct iscsi_param *param; 196 197 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set %s=%d\n", key, val); 198 param = spdk_iscsi_param_find(params, key); 199 if (param == NULL) { 200 SPDK_ERRLOG("no key %s\n", key); 201 return -1; 202 } 203 204 free(param->val); 205 snprintf(buf, sizeof buf, "%d", val); 206 207 param->val = strdup(buf); 208 209 return 0; 210 } 211 212 /** 213 * Parse a single KEY=VAL pair 214 * 215 * data = "KEY=VAL<NUL>" 216 */ 217 static int 218 spdk_iscsi_parse_param(struct iscsi_param **params, const uint8_t *data) 219 { 220 int rc; 221 uint8_t *key_copy; 222 const uint8_t *key_end, *val; 223 int key_len, val_len; 224 int max_len; 225 226 key_end = strchr(data, '='); 227 if (!key_end) { 228 SPDK_ERRLOG("'=' not found\n"); 229 return -1; 230 } 231 232 key_len = key_end - data; 233 if (key_len == 0) { 234 SPDK_ERRLOG("Empty key\n"); 235 return -1; 236 } 237 /* 238 * RFC 7143 6.1 239 */ 240 if (key_len > ISCSI_TEXT_MAX_KEY_LEN) { 241 SPDK_ERRLOG("Key name length is bigger than 63\n"); 242 return -1; 243 } 244 245 key_copy = malloc(key_len + 1); 246 if (!key_copy) { 247 SPDK_ERRLOG("malloc() failed for key_copy\n"); 248 return -ENOMEM; 249 } 250 251 memcpy(key_copy, data, key_len); 252 key_copy[key_len] = '\0'; 253 /* check whether this key is duplicated */ 254 if (NULL != spdk_iscsi_param_find(*params, key_copy)) { 255 SPDK_ERRLOG("Duplicated Key %s\n", key_copy); 256 free(key_copy); 257 return -1; 258 } 259 260 val = key_end + 1; /* +1 to skip over the '=' */ 261 val_len = strlen(val); 262 /* 263 * RFC 3720 5.1 264 * If not otherwise specified, the maximum length of a simple-value 265 * (not its encoded representation) is 255 bytes, not including the delimiter 266 * (comma or zero byte). 267 */ 268 /* 269 * comma or zero is counted in, otherwise we need to iterate each parameter 270 * value 271 */ 272 max_len = spdk_iscsi_find_key_in_array(key_copy, non_simple_value_params) ? 273 ISCSI_TEXT_MAX_VAL_LEN : ISCSI_TEXT_MAX_SIMPLE_VAL_LEN; 274 if (val_len > max_len) { 275 SPDK_ERRLOG("Overflow Val %d\n", val_len); 276 free(key_copy); 277 return -1; 278 } 279 280 rc = spdk_iscsi_param_add(params, key_copy, val, NULL, 0); 281 free(key_copy); 282 if (rc < 0) { 283 SPDK_ERRLOG("iscsi_param_add() failed\n"); 284 return -1; 285 } 286 287 /* return number of bytes consumed 288 * +1 for '=' and +1 for NUL 289 */ 290 return key_len + 1 + val_len + 1; 291 } 292 293 /** 294 * Parse a sequence of KEY=VAL pairs. 295 * 296 * \param data "KEY=VAL<NUL>KEY=VAL<NUL>..." 297 * \param len length of data in bytes 298 */ 299 int 300 spdk_iscsi_parse_params(struct iscsi_param **params, const uint8_t *data, 301 int len, bool cbit_enabled, char **partial_parameter) 302 { 303 int rc, offset = 0; 304 char *p; 305 int i; 306 307 /* strip the partial text parameters if previous PDU have C enabled */ 308 if (partial_parameter && *partial_parameter) { 309 for (i = 0; i < len && data[i] != '\0'; i++) { 310 ; 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 } 342 *partial_parameter = xstrdup(&data[i == 0 ? 0 : i + 1]); 343 len = (i == 0 ? 0 : i + 1); 344 } 345 346 while (offset < len && data[offset] != '\0') { 347 rc = spdk_iscsi_parse_param(params, data + offset); 348 if (rc < 0) { 349 return -1; 350 } 351 offset += rc; 352 } 353 return 0; 354 } 355 356 char * 357 spdk_iscsi_param_get_val(struct iscsi_param *params, const char *key) 358 { 359 struct iscsi_param *param; 360 361 param = spdk_iscsi_param_find(params, key); 362 if (param == NULL) { 363 return NULL; 364 } 365 return param->val; 366 } 367 368 int 369 spdk_iscsi_param_eq_val(struct iscsi_param *params, const char *key, 370 const char *val) 371 { 372 struct iscsi_param *param; 373 374 param = spdk_iscsi_param_find(params, key); 375 if (param == NULL) { 376 return 0; 377 } 378 if (strcasecmp(param->val, val) == 0) { 379 return 1; 380 } 381 return 0; 382 } 383 384 struct iscsi_param_table { 385 const char *key; 386 const char *val; 387 const char *list; 388 int type; 389 }; 390 391 static const struct iscsi_param_table conn_param_table[] = { 392 { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST }, 393 { "DataDigest", "None", "CRC32C,None", ISPT_LIST }, 394 { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL_DECLARATIVE }, 395 { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 396 { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND }, 397 { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 398 { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN }, 399 { "AuthMethod", "None", "CHAP,None", ISPT_LIST }, 400 { "CHAP_A", "5", "5", ISPT_LIST }, 401 { "CHAP_N", "", "", ISPT_DECLARATIVE }, 402 { "CHAP_R", "", "", ISPT_DECLARATIVE }, 403 { "CHAP_I", "", "", ISPT_DECLARATIVE }, 404 { "CHAP_C", "", "", ISPT_DECLARATIVE }, 405 { NULL, NULL, NULL, ISPT_INVALID }, 406 }; 407 408 static const struct iscsi_param_table sess_param_table[] = { 409 { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL_MIN }, 410 #if 0 411 /* need special handling */ 412 { "SendTargets", "", "", ISPT_DECLARATIVE }, 413 #endif 414 { "TargetName", "", "", ISPT_DECLARATIVE }, 415 { "InitiatorName", "", "", ISPT_DECLARATIVE }, 416 { "TargetAlias", "", "", ISPT_DECLARATIVE }, 417 { "InitiatorAlias", "", "", ISPT_DECLARATIVE }, 418 { "TargetAddress", "", "", ISPT_DECLARATIVE }, 419 { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL_DECLARATIVE }, 420 { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 421 { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND }, 422 { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL_MIN }, 423 { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL_MIN }, 424 { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX }, 425 { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL_MIN }, 426 { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL_MIN }, 427 { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 428 { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR }, 429 { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL_MIN }, 430 { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE }, 431 { NULL, NULL, NULL, ISPT_INVALID }, 432 }; 433 434 static int 435 spdk_iscsi_params_init_internal(struct iscsi_param **params, 436 const struct iscsi_param_table *table) 437 { 438 int rc; 439 int i; 440 struct iscsi_param *param; 441 442 for (i = 0; table[i].key != NULL; i++) { 443 rc = spdk_iscsi_param_add(params, table[i].key, table[i].val, 444 table[i].list, table[i].type); 445 if (rc < 0) { 446 SPDK_ERRLOG("iscsi_param_add() failed\n"); 447 return -1; 448 } 449 param = spdk_iscsi_param_find(*params, table[i].key); 450 if (param != NULL) { 451 param->state_index = i; 452 } else { 453 SPDK_ERRLOG("spdk_iscsi_param_find() failed\n"); 454 return -1; 455 } 456 } 457 458 return 0; 459 } 460 461 int 462 spdk_iscsi_conn_params_init(struct iscsi_param **params) 463 { 464 return spdk_iscsi_params_init_internal(params, &conn_param_table[0]); 465 } 466 467 int 468 spdk_iscsi_sess_params_init(struct iscsi_param **params) 469 { 470 return spdk_iscsi_params_init_internal(params, &sess_param_table[0]); 471 } 472 473 static const char *chap_type[] = { 474 "CHAP_A", 475 "CHAP_N", 476 "CHAP_R", 477 "CHAP_I", 478 "CHAP_C", 479 NULL, 480 }; 481 482 static const char *discovery_ignored_param[] = { 483 "MaxConnections", 484 "InitialR2T", 485 "ImmediateData", 486 "MaxBurstLength", 487 "FirstBurstLength" 488 "MaxOutstandingR2T", 489 "DataPDUInOrder", 490 NULL, 491 }; 492 493 static const char *multi_negot_conn_params[] = { 494 "MaxRecvDataSegmentLength", 495 NULL, 496 }; 497 498 /* The following params should be declared by target */ 499 static const char *target_declarative_params[] = { 500 "TargetAlias", 501 "TargetAddress", 502 "TargetPortalGroupTag", 503 NULL, 504 }; 505 506 /* This function is used to contruct the data from the special param (e.g., 507 * MaxRecvDataSegmentLength) 508 * return: 509 * normal: the total len of the data 510 * error: -1 511 */ 512 static int 513 spdk_iscsi_special_param_construction(struct spdk_iscsi_conn *conn, 514 struct iscsi_param *param, 515 bool FirstBurstLength_flag, char *data, 516 int alloc_len, int total) 517 { 518 int len; 519 struct iscsi_param *param_first; 520 struct iscsi_param *param_max; 521 uint32_t FirstBurstLength; 522 uint32_t MaxBurstLength; 523 char *val; 524 525 val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 526 if (!val) { 527 SPDK_ERRLOG("malloc() failed for temporary buffer\n"); 528 return -ENOMEM; 529 } 530 531 if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) { 532 /* 533 * MaxRecvDataSegmentLength is sent by both 534 * initiator and target, but is declarative - meaning 535 * each direction can have different values. 536 * So when MaxRecvDataSegmentLength is found in the 537 * the parameter set sent from the initiator, add SPDK 538 * iscsi target's MaxRecvDataSegmentLength value to 539 * the returned parameter list. 540 */ 541 if (alloc_len - total < 1) { 542 SPDK_ERRLOG("data space small %d\n", alloc_len); 543 free(val); 544 return -1; 545 } 546 547 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 548 "returning MaxRecvDataSegmentLength=%d\n", 549 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 550 len = snprintf((char *)data + total, alloc_len - total, 551 "MaxRecvDataSegmentLength=%d", 552 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH); 553 total += len + 1; 554 } 555 556 if (strcasecmp(param->key, "MaxBurstLength") == 0 && 557 !FirstBurstLength_flag) { 558 if (alloc_len - total < 1) { 559 SPDK_ERRLOG("data space small %d\n", alloc_len); 560 free(val); 561 return -1; 562 } 563 564 param_first = spdk_iscsi_param_find(conn->sess->params, 565 "FirstBurstLength"); 566 if (param_first != NULL) { 567 FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10); 568 } else { 569 FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH; 570 } 571 param_max = spdk_iscsi_param_find(conn->sess->params, 572 "MaxBurstLength"); 573 if (param_max != NULL) { 574 MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10); 575 } else { 576 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 577 } 578 579 if (FirstBurstLength > MaxBurstLength) { 580 FirstBurstLength = MaxBurstLength; 581 if (param_first != NULL) { 582 free(param_first->val); 583 snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 584 FirstBurstLength); 585 param_first->val = xstrdup(val); 586 } 587 } 588 len = snprintf((char *)data + total, alloc_len - total, 589 "FirstBurstLength=%d", FirstBurstLength); 590 total += len + 1; 591 } 592 593 free(val); 594 return total; 595 596 } 597 598 /** 599 * spdk_iscsi_construct_data_from_param: 600 * To construct the data which will be returned to the initiator 601 * return: length of the negotiated data, -1 inidicates error; 602 */ 603 static int 604 spdk_iscsi_construct_data_from_param(struct iscsi_param *param, char *new_val, 605 char *data, int alloc_len, int total) 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 * To negotiate param with 627 * type = ISPT_LIST 628 * return: the negotiated value of the key 629 */ 630 static char *spdk_iscsi_negotiate_param_list(int *add_param_value, 631 struct iscsi_param *param, 632 char *valid_list, char *in_val, 633 char *cur_val) 634 { 635 char *val_start, *val_end; 636 char *in_start, *in_end; 637 int flag = 0; 638 639 if (add_param_value == NULL) { 640 return NULL; 641 } 642 643 in_start = in_val; 644 do { 645 if ((in_end = strchr(in_start, (int)',')) != NULL) { 646 *in_end = '\0'; 647 } 648 val_start = valid_list; 649 do { 650 if ((val_end = strchr(val_start, (int)',')) != NULL) { 651 *val_end = '\0'; 652 } 653 if (strcasecmp(in_start, val_start) == 0) { 654 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "match %s\n", 655 val_start); 656 flag = 1; 657 break; 658 } 659 if (val_end) { 660 *val_end = ','; 661 val_start = val_end + 1; 662 } 663 } while (val_end); 664 if (flag) { 665 break; 666 } 667 if (in_end) { 668 *in_end = ','; 669 in_start = in_end + 1; 670 } 671 } while (in_end); 672 673 return flag ? val_start : NULL; 674 } 675 676 /** 677 * To negotiate param with 678 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE 679 * return: the negotiated value of the key 680 */ 681 static char *spdk_iscsi_negotiate_param_numerical(int *add_param_value, 682 struct iscsi_param *param, 683 char *valid_list, char *in_val, 684 char *cur_val) 685 { 686 char *valid_next; 687 char *new_val = NULL; 688 char *min_val, *max_val; 689 int val_i, cur_val_i; 690 int min_i, max_i; 691 692 if (add_param_value == NULL) { 693 return NULL; 694 } 695 696 val_i = (int)strtol(param->val, NULL, 10); 697 /* check whether the key is FirstBurstLength, if that we use in_val */ 698 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 699 val_i = (int)strtol(in_val, NULL, 10); 700 } 701 702 cur_val_i = (int)strtol(cur_val, NULL, 10); 703 valid_next = valid_list; 704 min_val = spdk_strsepq(&valid_next, ","); 705 max_val = spdk_strsepq(&valid_next, ","); 706 min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0; 707 max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0; 708 if (val_i < min_i || val_i > max_i) { 709 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "key %.64s reject\n", param->key); 710 new_val = NULL; 711 } else { 712 switch (param->type) { 713 case ISPT_NUMERICAL_MIN: 714 if (val_i > cur_val_i) { 715 val_i = cur_val_i; 716 } 717 break; 718 case ISPT_NUMERICAL_MAX: 719 if (val_i < cur_val_i) { 720 val_i = cur_val_i; 721 } 722 break; 723 default: 724 break; 725 } 726 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i); 727 new_val = in_val; 728 } 729 730 return new_val; 731 } 732 733 /** 734 * To negotiate param with 735 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND 736 * return: the negotiated value of the key 737 */ 738 static char *spdk_iscsi_negotiate_param_boolean(int *add_param_value, 739 struct iscsi_param *param, 740 char *in_val, char *cur_val, 741 const char *value) 742 { 743 char *new_val = NULL; 744 745 if (add_param_value == NULL) { 746 return NULL; 747 } 748 749 /* Make sure the val is Yes or No */ 750 if (!((strcasecmp(in_val, "Yes") == 0) || 751 (strcasecmp(in_val, "No") == 0))) { 752 /* unknown value */ 753 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject"); 754 new_val = in_val; 755 *add_param_value = 1; 756 return new_val; 757 } 758 759 if (strcasecmp(cur_val, value) == 0) { 760 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value); 761 new_val = in_val; 762 } else { 763 new_val = param->val; 764 } 765 766 return new_val; 767 } 768 769 /** 770 * The entry function to handle each type of the param 771 * return value: the new negotiated value 772 */ 773 static char * 774 spdk_iscsi_negotiate_param_all(int *add_param_value, struct iscsi_param *param, 775 char *valid_list, char *in_val, char *cur_val) 776 { 777 char *new_val; 778 switch (param->type) { 779 case ISPT_LIST: 780 new_val = spdk_iscsi_negotiate_param_list(add_param_value, 781 param, 782 valid_list, 783 in_val, 784 cur_val); 785 break; 786 787 case ISPT_NUMERICAL_MIN: 788 case ISPT_NUMERICAL_MAX: 789 case ISPT_NUMERICAL_DECLARATIVE: 790 new_val = spdk_iscsi_negotiate_param_numerical(add_param_value, 791 param, 792 valid_list, 793 in_val, 794 cur_val); 795 break; 796 797 case ISPT_BOOLEAN_OR: 798 new_val = spdk_iscsi_negotiate_param_boolean(add_param_value, 799 param, 800 in_val, 801 cur_val, 802 "Yes"); 803 break; 804 case ISPT_BOOLEAN_AND: 805 new_val = spdk_iscsi_negotiate_param_boolean(add_param_value, 806 param, 807 in_val, 808 cur_val, 809 "No"); 810 break; 811 812 default: 813 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 814 new_val = in_val; 815 break; 816 } 817 818 return new_val; 819 } 820 821 /** 822 * This function is used to judge whether the param is in session's params or 823 * connection's params 824 */ 825 static int 826 spdk_iscsi_negotiate_param_init(struct spdk_iscsi_conn *conn, 827 struct iscsi_param **cur_param_p, 828 struct iscsi_param **params_dst_p, 829 struct iscsi_param *param) 830 { 831 int index; 832 833 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 834 if (*cur_param_p == NULL) { 835 *params_dst_p = conn->sess->params; 836 *cur_param_p = spdk_iscsi_param_find(*params_dst_p, param->key); 837 if (*cur_param_p == NULL) { 838 if ((strncasecmp(param->key, "X-", 2) == 0) || 839 (strncasecmp(param->key, "X#", 2) == 0)) { 840 /* Extension Key */ 841 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 842 "extension key %.64s\n", 843 param->key); 844 } else { 845 SPDK_ERRLOG("unknown key %.64s\n", param->key); 846 } 847 return 1; 848 } else { 849 index = (*cur_param_p)->state_index; 850 if (conn->sess_param_state_negotiated[index] && 851 !spdk_iscsi_find_key_in_array(param->key, 852 target_declarative_params)) { 853 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 854 } 855 conn->sess_param_state_negotiated[index] = true; 856 } 857 } else { 858 index = (*cur_param_p)->state_index; 859 if (conn->conn_param_state_negotiated[index] && 860 !spdk_iscsi_find_key_in_array(param->key, 861 multi_negot_conn_params)) { 862 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE; 863 } 864 conn->conn_param_state_negotiated[index] = true; 865 } 866 867 return 0; 868 } 869 870 int 871 spdk_iscsi_negotiate_params(struct spdk_iscsi_conn *conn, 872 struct iscsi_param **params, uint8_t *data, int alloc_len, 873 int data_len) 874 { 875 struct iscsi_param *param; 876 struct iscsi_param *cur_param; 877 char *valid_list, *in_val; 878 char *cur_val; 879 char *new_val; 880 int discovery; 881 int total; 882 int rc; 883 uint32_t FirstBurstLength; 884 uint32_t MaxBurstLength; 885 bool FirstBurstLength_flag = false; 886 int type; 887 888 total = data_len; 889 if (alloc_len < 1) { 890 return 0; 891 } 892 if (total > alloc_len) { 893 total = alloc_len; 894 data[total - 1] = '\0'; 895 return total; 896 } 897 898 if (*params == NULL) { 899 /* no input */ 900 return total; 901 } 902 903 /* discovery? */ 904 discovery = 0; 905 cur_param = spdk_iscsi_param_find(*params, "SessionType"); 906 if (cur_param == NULL) { 907 cur_param = spdk_iscsi_param_find(conn->sess->params, "SessionType"); 908 if (cur_param == NULL) { 909 /* no session type */ 910 } else { 911 if (strcasecmp(cur_param->val, "Discovery") == 0) { 912 discovery = 1; 913 } 914 } 915 } else { 916 if (strcasecmp(cur_param->val, "Discovery") == 0) { 917 discovery = 1; 918 } 919 } 920 921 /* for temporary store */ 922 valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 923 if (!valid_list) { 924 SPDK_ERRLOG("malloc() failed for valid_list\n"); 925 return -ENOMEM; 926 } 927 928 in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 929 if (!in_val) { 930 SPDK_ERRLOG("malloc() failed for in_val\n"); 931 free(valid_list); 932 return -ENOMEM; 933 } 934 935 cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1); 936 if (!cur_val) { 937 SPDK_ERRLOG("malloc() failed for cur_val\n"); 938 free(valid_list); 939 free(in_val); 940 return -ENOMEM; 941 } 942 943 /* To adjust the location of FirstBurstLength location and put it to 944 * the end, then we can always firstly determine the MaxBurstLength 945 */ 946 param = spdk_iscsi_param_find(*params, "MaxBurstLength"); 947 if (param != NULL) { 948 param = spdk_iscsi_param_find(*params, "FirstBurstLength"); 949 950 /* check the existence of FirstBurstLength */ 951 if (param != NULL) { 952 FirstBurstLength_flag = true; 953 if (param->next != NULL) { 954 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 955 type = param->type; 956 spdk_iscsi_param_add(params, "FirstBurstLength", 957 in_val, NULL, type); 958 } 959 } 960 } 961 962 for (param = *params; param != NULL; param = param->next) { 963 struct iscsi_param *params_dst = conn->params; 964 int add_param_value = 0; 965 new_val = NULL; 966 param->type = ISPT_INVALID; 967 968 /* sendtargets is special */ 969 if (strcasecmp(param->key, "SendTargets") == 0) { 970 continue; 971 } 972 /* CHAP keys */ 973 if (spdk_iscsi_find_key_in_array(param->key, chap_type)) { 974 continue; 975 } 976 977 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */ 978 if (discovery && 979 spdk_iscsi_find_key_in_array(param->key, 980 discovery_ignored_param)) { 981 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant"); 982 new_val = in_val; 983 add_param_value = 1; 984 } else { 985 rc = spdk_iscsi_negotiate_param_init(conn, 986 &cur_param, 987 ¶ms_dst, 988 param); 989 if (rc < 0) { 990 free(valid_list); 991 free(in_val); 992 free(cur_val); 993 return rc; 994 } else if (rc > 0) { 995 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood"); 996 new_val = in_val; 997 add_param_value = 1; 998 } else { 999 snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list); 1000 snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val); 1001 param->type = cur_param->type; 1002 } 1003 } 1004 1005 if (param->type > 0) { 1006 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val); 1007 1008 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */ 1009 if (strcasecmp(in_val, "NotUnderstood") == 0) { 1010 free(in_val); 1011 free(valid_list); 1012 free(cur_val); 1013 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER; 1014 } 1015 1016 if (strcasecmp(param->key, "FirstBurstLength") == 0) { 1017 FirstBurstLength = (uint32_t)strtol(param->val, NULL, 1018 10); 1019 new_val = spdk_iscsi_param_get_val(conn->sess->params, 1020 "MaxBurstLength"); 1021 if (new_val != NULL) { 1022 MaxBurstLength = (uint32_t) strtol(new_val, NULL, 1023 10); 1024 } else { 1025 MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH; 1026 } 1027 if (FirstBurstLength < MAX_FIRSTBURSTLENGTH && 1028 FirstBurstLength > MaxBurstLength) { 1029 FirstBurstLength = MaxBurstLength; 1030 snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", 1031 FirstBurstLength); 1032 } 1033 } 1034 1035 /* prevent target's declarative params from being changed by initiator */ 1036 if (spdk_iscsi_find_key_in_array(param->key, target_declarative_params)) { 1037 add_param_value = 1; 1038 } 1039 1040 new_val = spdk_iscsi_negotiate_param_all(&add_param_value, 1041 param, 1042 valid_list, 1043 in_val, 1044 cur_val); 1045 } 1046 1047 /* check the negotiated value of the key */ 1048 if (new_val != NULL) { 1049 /* add_param_value = 0 means updating the value of 1050 * existed key in the connection's parameters 1051 */ 1052 if (add_param_value == 0) { 1053 spdk_iscsi_param_set(params_dst, param->key, new_val); 1054 } 1055 total = spdk_iscsi_construct_data_from_param(param, 1056 new_val, 1057 data, 1058 alloc_len, 1059 total); 1060 if (total < 0) { 1061 goto final_return; 1062 } 1063 1064 total = spdk_iscsi_special_param_construction(conn, 1065 param, 1066 FirstBurstLength_flag, 1067 data, 1068 alloc_len, 1069 total); 1070 if (total < 0) { 1071 goto final_return; 1072 } 1073 } else { 1074 total = -1; 1075 break; 1076 } 1077 } 1078 1079 final_return: 1080 free(valid_list); 1081 free(in_val); 1082 free(cur_val); 1083 1084 return total; 1085 } 1086 1087 int 1088 spdk_iscsi_copy_param2var(struct spdk_iscsi_conn *conn) 1089 { 1090 const char *val; 1091 1092 val = spdk_iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength"); 1093 if (val == NULL) { 1094 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n"); 1095 return -1; 1096 } 1097 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, 1098 "copy MaxRecvDataSegmentLength=%s\n", val); 1099 conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10); 1100 if (conn->MaxRecvDataSegmentLength > SPDK_ISCSI_MAX_SEND_DATA_SEGMENT_LENGTH) { 1101 conn->MaxRecvDataSegmentLength = SPDK_ISCSI_MAX_SEND_DATA_SEGMENT_LENGTH; 1102 } 1103 1104 val = spdk_iscsi_param_get_val(conn->params, "HeaderDigest"); 1105 if (val == NULL) { 1106 SPDK_ERRLOG("Getval HeaderDigest failed\n"); 1107 return -1; 1108 } 1109 if (strcasecmp(val, "CRC32C") == 0) { 1110 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=1\n"); 1111 conn->header_digest = 1; 1112 } else { 1113 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=0\n"); 1114 conn->header_digest = 0; 1115 } 1116 val = spdk_iscsi_param_get_val(conn->params, "DataDigest"); 1117 if (val == NULL) { 1118 SPDK_ERRLOG("Getval DataDigest failed\n"); 1119 return -1; 1120 } 1121 if (strcasecmp(val, "CRC32C") == 0) { 1122 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=1\n"); 1123 conn->data_digest = 1; 1124 } else { 1125 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=0\n"); 1126 conn->data_digest = 0; 1127 } 1128 1129 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxConnections"); 1130 if (val == NULL) { 1131 SPDK_ERRLOG("Getval MaxConnections failed\n"); 1132 return -1; 1133 } 1134 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxConnections=%s\n", val); 1135 conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10); 1136 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T"); 1137 if (val == NULL) { 1138 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n"); 1139 return -1; 1140 } 1141 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxOutstandingR2T=%s\n", val); 1142 conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10); 1143 val = spdk_iscsi_param_get_val(conn->sess->params, "FirstBurstLength"); 1144 if (val == NULL) { 1145 SPDK_ERRLOG("Getval FirstBurstLength failed\n"); 1146 return -1; 1147 } 1148 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy FirstBurstLength=%s\n", val); 1149 conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10); 1150 val = spdk_iscsi_param_get_val(conn->sess->params, "MaxBurstLength"); 1151 if (val == NULL) { 1152 SPDK_ERRLOG("Getval MaxBurstLength failed\n"); 1153 return -1; 1154 } 1155 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxBurstLength=%s\n", val); 1156 conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10); 1157 val = spdk_iscsi_param_get_val(conn->sess->params, "InitialR2T"); 1158 if (val == NULL) { 1159 SPDK_ERRLOG("Getval InitialR2T failed\n"); 1160 return -1; 1161 } 1162 if (strcasecmp(val, "Yes") == 0) { 1163 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=1\n"); 1164 conn->sess->InitialR2T = true; 1165 } else { 1166 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=0\n"); 1167 conn->sess->InitialR2T = false; 1168 } 1169 val = spdk_iscsi_param_get_val(conn->sess->params, "ImmediateData"); 1170 if (val == NULL) { 1171 SPDK_ERRLOG("Getval ImmediateData failed\n"); 1172 return -1; 1173 } 1174 if (strcasecmp(val, "Yes") == 0) { 1175 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=1\n"); 1176 conn->sess->ImmediateData = true; 1177 } else { 1178 SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=0\n"); 1179 conn->sess->ImmediateData = false; 1180 } 1181 return 0; 1182 } 1183