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