4 * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5 * Copyright (c) Intel Corporation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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.
35 #include "spdk/stdinc.h"
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"
43 #include "spdk_internal/log.h"
45 #define MAX_TMPBUF 1024
47 /* whose value may be bigger than 255 */
48 static const char *non_simple_value_params
[] = {
55 spdk_iscsi_param_free(struct iscsi_param
*params
)
57 struct iscsi_param
*param
, *next_param
;
62 for (param
= params
; param
!= NULL
; param
= next_param
) {
63 next_param
= param
->next
;
74 iscsi_find_key_in_array(const char *key
, const char *array
[])
78 for (i
= 0; array
[i
] != NULL
; i
++) {
79 if (strcasecmp(key
, array
[i
]) == 0) {
87 spdk_iscsi_param_find(struct iscsi_param
*params
, const char *key
)
89 struct iscsi_param
*param
;
91 if (params
== NULL
|| key
== NULL
) {
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) {
104 spdk_iscsi_param_del(struct iscsi_param
**params
, const char *key
)
106 struct iscsi_param
*param
, *prev_param
= NULL
;
108 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "del %s\n", key
);
109 if (params
== NULL
|| key
== NULL
) {
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
;
118 *params
= param
->next
;
121 spdk_iscsi_param_free(param
);
130 spdk_iscsi_param_add(struct iscsi_param
**params
, const char *key
,
131 const char *val
, const char *list
, int type
)
133 struct iscsi_param
*param
, *last_param
;
135 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "add %s=%s, list=[%s], type=%d\n",
136 key
, val
, list
, type
);
141 param
= spdk_iscsi_param_find(*params
, key
);
143 spdk_iscsi_param_del(params
, key
);
146 param
= calloc(1, sizeof(*param
));
148 SPDK_ERRLOG("calloc() failed for parameter\n");
153 param
->key
= xstrdup(key
);
154 param
->val
= xstrdup(val
);
155 param
->list
= xstrdup(list
);
158 last_param
= *params
;
159 if (last_param
!= NULL
) {
160 while (last_param
->next
!= NULL
) {
161 last_param
= last_param
->next
;
163 last_param
->next
= param
;
172 spdk_iscsi_param_set(struct iscsi_param
*params
, const char *key
,
175 struct iscsi_param
*param
;
177 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set %s=%s\n", key
, val
);
178 param
= spdk_iscsi_param_find(params
, key
);
180 SPDK_ERRLOG("no key %s\n", key
);
186 param
->val
= xstrdup(val
);
192 spdk_iscsi_param_set_int(struct iscsi_param
*params
, const char *key
, uint32_t val
)
194 char buf
[MAX_TMPBUF
];
195 struct iscsi_param
*param
;
197 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set %s=%d\n", key
, val
);
198 param
= spdk_iscsi_param_find(params
, key
);
200 SPDK_ERRLOG("no key %s\n", key
);
205 snprintf(buf
, sizeof buf
, "%d", val
);
207 param
->val
= strdup(buf
);
213 * Parse a single KEY=VAL pair
215 * data = "KEY=VAL<NUL>"
218 iscsi_parse_param(struct iscsi_param
**params
, const uint8_t *data
, uint32_t data_len
)
221 uint8_t *key_copy
, *val_copy
;
222 const uint8_t *key_end
;
223 int key_len
, val_len
;
226 data_len
= strnlen(data
, data_len
);
227 /* No such thing as strnchr so use memchr instead. */
228 key_end
= memchr(data
, '=', data_len
);
230 SPDK_ERRLOG("'=' not found\n");
234 key_len
= key_end
- data
;
236 SPDK_ERRLOG("Empty key\n");
242 if (key_len
> ISCSI_TEXT_MAX_KEY_LEN
) {
243 SPDK_ERRLOG("Key name length is bigger than 63\n");
247 key_copy
= malloc(key_len
+ 1);
249 SPDK_ERRLOG("malloc() failed for key_copy\n");
253 memcpy(key_copy
, data
, key_len
);
254 key_copy
[key_len
] = '\0';
255 /* check whether this key is duplicated */
256 if (NULL
!= spdk_iscsi_param_find(*params
, key_copy
)) {
257 SPDK_ERRLOG("Duplicated Key %s\n", key_copy
);
262 val_len
= strnlen(key_end
+ 1, data_len
- key_len
- 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).
270 * comma or zero is counted in, otherwise we need to iterate each parameter
273 max_len
= iscsi_find_key_in_array(key_copy
, non_simple_value_params
) ?
274 ISCSI_TEXT_MAX_VAL_LEN
: ISCSI_TEXT_MAX_SIMPLE_VAL_LEN
;
275 if (val_len
> max_len
) {
276 SPDK_ERRLOG("Overflow Val %d\n", val_len
);
281 val_copy
= calloc(1, val_len
+ 1);
282 if (val_copy
== NULL
) {
283 SPDK_ERRLOG("Could not allocate value string\n");
288 memcpy(val_copy
, key_end
+ 1, val_len
);
290 rc
= spdk_iscsi_param_add(params
, key_copy
, val_copy
, NULL
, 0);
294 SPDK_ERRLOG("iscsi_param_add() failed\n");
298 /* return number of bytes consumed
299 * +1 for '=' and +1 for NUL
301 return key_len
+ 1 + val_len
+ 1;
305 * Parse a sequence of KEY=VAL pairs.
307 * \param data "KEY=VAL<NUL>KEY=VAL<NUL>..."
308 * \param len length of data in bytes
311 spdk_iscsi_parse_params(struct iscsi_param
**params
, const uint8_t *data
,
312 int len
, bool cbit_enabled
, char **partial_parameter
)
318 /* strip the partial text parameters if previous PDU have C enabled */
319 if (partial_parameter
&& *partial_parameter
) {
320 for (i
= 0; i
< len
&& data
[i
] != '\0'; i
++) {
323 p
= spdk_sprintf_alloc("%s%s", *partial_parameter
, (const char *)data
);
327 rc
= iscsi_parse_param(params
, p
, i
+ strlen(*partial_parameter
));
332 free(*partial_parameter
);
333 *partial_parameter
= NULL
;
339 /* strip the partial text parameters if C bit is enabled */
341 if (partial_parameter
== NULL
) {
342 SPDK_ERRLOG("C bit set but no partial parameters provided\n");
347 * reverse iterate the string from the tail not including '\0'
349 for (i
= len
- 1; data
[i
] != '\0' && i
> 0; i
--) {
353 /* We found a NULL character - don't copy it into the
359 *partial_parameter
= calloc(1, len
- i
+ 1);
360 if (*partial_parameter
== NULL
) {
361 SPDK_ERRLOG("could not allocate partial parameter\n");
364 memcpy(*partial_parameter
, &data
[i
], len
- i
);
366 /* No full parameters to parse - so return now. */
373 while (offset
< len
&& data
[offset
] != '\0') {
374 rc
= iscsi_parse_param(params
, data
+ offset
, len
- offset
);
384 spdk_iscsi_param_get_val(struct iscsi_param
*params
, const char *key
)
386 struct iscsi_param
*param
;
388 param
= spdk_iscsi_param_find(params
, key
);
396 spdk_iscsi_param_eq_val(struct iscsi_param
*params
, const char *key
,
399 struct iscsi_param
*param
;
401 param
= spdk_iscsi_param_find(params
, key
);
405 if (strcasecmp(param
->val
, val
) == 0) {
411 struct iscsi_param_table
{
418 static const struct iscsi_param_table conn_param_table
[] = {
419 { "HeaderDigest", "None", "CRC32C,None", ISPT_LIST
},
420 { "DataDigest", "None", "CRC32C,None", ISPT_LIST
},
421 { "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL_DECLARATIVE
},
422 { "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND
},
423 { "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND
},
424 { "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN
},
425 { "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN
},
426 { "AuthMethod", "None", "CHAP,None", ISPT_LIST
},
427 { "CHAP_A", "5", "5", ISPT_LIST
},
428 { "CHAP_N", "", "", ISPT_DECLARATIVE
},
429 { "CHAP_R", "", "", ISPT_DECLARATIVE
},
430 { "CHAP_I", "", "", ISPT_DECLARATIVE
},
431 { "CHAP_C", "", "", ISPT_DECLARATIVE
},
432 { NULL
, NULL
, NULL
, ISPT_INVALID
},
435 static const struct iscsi_param_table sess_param_table
[] = {
436 { "MaxConnections", "1", "1,65535", ISPT_NUMERICAL_MIN
},
438 /* need special handling */
439 { "SendTargets", "", "", ISPT_DECLARATIVE
},
441 { "TargetName", "", "", ISPT_DECLARATIVE
},
442 { "InitiatorName", "", "", ISPT_DECLARATIVE
},
443 { "TargetAlias", "", "", ISPT_DECLARATIVE
},
444 { "InitiatorAlias", "", "", ISPT_DECLARATIVE
},
445 { "TargetAddress", "", "", ISPT_DECLARATIVE
},
446 { "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL_DECLARATIVE
},
447 { "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR
},
448 { "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND
},
449 { "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL_MIN
},
450 { "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL_MIN
},
451 { "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX
},
452 { "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL_MIN
},
453 { "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL_MIN
},
454 { "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR
},
455 { "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR
},
456 { "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL_MIN
},
457 { "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE
},
458 { NULL
, NULL
, NULL
, ISPT_INVALID
},
462 iscsi_params_init_internal(struct iscsi_param
**params
,
463 const struct iscsi_param_table
*table
)
467 struct iscsi_param
*param
;
469 for (i
= 0; table
[i
].key
!= NULL
; i
++) {
470 rc
= spdk_iscsi_param_add(params
, table
[i
].key
, table
[i
].val
,
471 table
[i
].list
, table
[i
].type
);
473 SPDK_ERRLOG("iscsi_param_add() failed\n");
476 param
= spdk_iscsi_param_find(*params
, table
[i
].key
);
478 param
->state_index
= i
;
480 SPDK_ERRLOG("spdk_iscsi_param_find() failed\n");
489 spdk_iscsi_conn_params_init(struct iscsi_param
**params
)
491 return iscsi_params_init_internal(params
, &conn_param_table
[0]);
495 spdk_iscsi_sess_params_init(struct iscsi_param
**params
)
497 return iscsi_params_init_internal(params
, &sess_param_table
[0]);
500 static const char *chap_type
[] = {
509 static const char *discovery_ignored_param
[] = {
520 static const char *multi_negot_conn_params
[] = {
521 "MaxRecvDataSegmentLength",
525 /* The following params should be declared by target */
526 static const char *target_declarative_params
[] = {
529 "TargetPortalGroupTag",
533 /* This function is used to construct the data from the special param (e.g.,
534 * MaxRecvDataSegmentLength)
536 * normal: the total len of the data
540 iscsi_special_param_construction(struct spdk_iscsi_conn
*conn
,
541 struct iscsi_param
*param
,
542 bool FirstBurstLength_flag
, char *data
,
543 int alloc_len
, int total
)
546 struct iscsi_param
*param_first
;
547 struct iscsi_param
*param_max
;
548 uint32_t FirstBurstLength
;
549 uint32_t MaxBurstLength
;
552 val
= malloc(ISCSI_TEXT_MAX_VAL_LEN
+ 1);
554 SPDK_ERRLOG("malloc() failed for temporary buffer\n");
558 if (strcasecmp(param
->key
, "MaxRecvDataSegmentLength") == 0) {
560 * MaxRecvDataSegmentLength is sent by both
561 * initiator and target, but is declarative - meaning
562 * each direction can have different values.
563 * So when MaxRecvDataSegmentLength is found in the
564 * the parameter set sent from the initiator, add SPDK
565 * iscsi target's MaxRecvDataSegmentLength value to
566 * the returned parameter list.
568 if (alloc_len
- total
< 1) {
569 SPDK_ERRLOG("data space small %d\n", alloc_len
);
574 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
,
575 "returning MaxRecvDataSegmentLength=%d\n",
576 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH
);
577 len
= snprintf((char *)data
+ total
, alloc_len
- total
,
578 "MaxRecvDataSegmentLength=%d",
579 SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH
);
583 if (strcasecmp(param
->key
, "MaxBurstLength") == 0 &&
584 !FirstBurstLength_flag
) {
585 if (alloc_len
- total
< 1) {
586 SPDK_ERRLOG("data space small %d\n", alloc_len
);
591 param_first
= spdk_iscsi_param_find(conn
->sess
->params
,
593 if (param_first
!= NULL
) {
594 FirstBurstLength
= (uint32_t)strtol(param_first
->val
, NULL
, 10);
596 FirstBurstLength
= SPDK_ISCSI_FIRST_BURST_LENGTH
;
598 param_max
= spdk_iscsi_param_find(conn
->sess
->params
,
600 if (param_max
!= NULL
) {
601 MaxBurstLength
= (uint32_t)strtol(param_max
->val
, NULL
, 10);
603 MaxBurstLength
= SPDK_ISCSI_MAX_BURST_LENGTH
;
606 if (FirstBurstLength
> MaxBurstLength
) {
607 FirstBurstLength
= MaxBurstLength
;
608 if (param_first
!= NULL
) {
609 free(param_first
->val
);
610 snprintf(val
, ISCSI_TEXT_MAX_VAL_LEN
, "%d",
612 param_first
->val
= xstrdup(val
);
615 len
= snprintf((char *)data
+ total
, alloc_len
- total
,
616 "FirstBurstLength=%d", FirstBurstLength
);
626 * iscsi_construct_data_from_param:
627 * To construct the data which will be returned to the initiator
628 * return: length of the negotiated data, -1 indicates error;
631 iscsi_construct_data_from_param(struct iscsi_param
*param
, char *new_val
,
632 char *data
, int alloc_len
, int total
)
636 if (param
->type
!= ISPT_DECLARATIVE
&&
637 param
->type
!= ISPT_NUMERICAL_DECLARATIVE
) {
638 if (alloc_len
- total
< 1) {
639 SPDK_ERRLOG("data space small %d\n", alloc_len
);
643 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "negotiated %s=%s\n",
644 param
->key
, new_val
);
645 len
= snprintf((char *)data
+ total
, alloc_len
- total
, "%s=%s",
646 param
->key
, new_val
);
653 * To negotiate param with
655 * return: the negotiated value of the key
658 iscsi_negotiate_param_list(int *add_param_value
,
659 struct iscsi_param
*param
,
660 char *valid_list
, char *in_val
,
663 char *val_start
, *val_end
;
664 char *in_start
, *in_end
;
667 if (add_param_value
== NULL
) {
673 if ((in_end
= strchr(in_start
, (int)',')) != NULL
) {
676 val_start
= valid_list
;
678 if ((val_end
= strchr(val_start
, (int)',')) != NULL
) {
681 if (strcasecmp(in_start
, val_start
) == 0) {
682 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "match %s\n",
689 val_start
= val_end
+ 1;
697 in_start
= in_end
+ 1;
701 return flag
? val_start
: NULL
;
705 * To negotiate param with
706 * type = ISPT_NUMERICAL_MIN/MAX, ISPT_NUMERICAL_DECLARATIVE
707 * return: the negotiated value of the key
710 iscsi_negotiate_param_numerical(int *add_param_value
,
711 struct iscsi_param
*param
,
712 char *valid_list
, char *in_val
,
716 char *new_val
= NULL
;
717 char *min_val
, *max_val
;
718 int val_i
, cur_val_i
;
721 if (add_param_value
== NULL
) {
725 val_i
= (int)strtol(param
->val
, NULL
, 10);
726 /* check whether the key is FirstBurstLength, if that we use in_val */
727 if (strcasecmp(param
->key
, "FirstBurstLength") == 0) {
728 val_i
= (int)strtol(in_val
, NULL
, 10);
731 cur_val_i
= (int)strtol(cur_val
, NULL
, 10);
732 valid_next
= valid_list
;
733 min_val
= spdk_strsepq(&valid_next
, ",");
734 max_val
= spdk_strsepq(&valid_next
, ",");
735 min_i
= (min_val
!= NULL
) ? (int)strtol(min_val
, NULL
, 10) : 0;
736 max_i
= (max_val
!= NULL
) ? (int)strtol(max_val
, NULL
, 10) : 0;
737 if (val_i
< min_i
|| val_i
> max_i
) {
738 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "key %.64s reject\n", param
->key
);
741 switch (param
->type
) {
742 case ISPT_NUMERICAL_MIN
:
743 if (val_i
> cur_val_i
) {
747 case ISPT_NUMERICAL_MAX
:
748 if (val_i
< cur_val_i
) {
755 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
, "%d", val_i
);
763 * To negotiate param with
764 * type = ISPT_BOOLEAN_OR, ISPT_BOOLEAN_AND
765 * return: the negotiated value of the key
768 iscsi_negotiate_param_boolean(int *add_param_value
,
769 struct iscsi_param
*param
,
770 char *in_val
, char *cur_val
,
773 char *new_val
= NULL
;
775 if (add_param_value
== NULL
) {
779 /* Make sure the val is Yes or No */
780 if (!((strcasecmp(in_val
, "Yes") == 0) ||
781 (strcasecmp(in_val
, "No") == 0))) {
783 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", "Reject");
785 *add_param_value
= 1;
789 if (strcasecmp(cur_val
, value
) == 0) {
790 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", value
);
793 new_val
= param
->val
;
800 * The entry function to handle each type of the param
801 * return value: the new negotiated value
804 iscsi_negotiate_param_all(int *add_param_value
, struct iscsi_param
*param
,
805 char *valid_list
, char *in_val
, char *cur_val
)
808 switch (param
->type
) {
810 new_val
= iscsi_negotiate_param_list(add_param_value
,
817 case ISPT_NUMERICAL_MIN
:
818 case ISPT_NUMERICAL_MAX
:
819 case ISPT_NUMERICAL_DECLARATIVE
:
820 new_val
= iscsi_negotiate_param_numerical(add_param_value
,
827 case ISPT_BOOLEAN_OR
:
828 new_val
= iscsi_negotiate_param_boolean(add_param_value
,
834 case ISPT_BOOLEAN_AND
:
835 new_val
= iscsi_negotiate_param_boolean(add_param_value
,
843 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", param
->val
);
852 * This function is used to judge whether the param is in session's params or
853 * connection's params
856 iscsi_negotiate_param_init(struct spdk_iscsi_conn
*conn
,
857 struct iscsi_param
**cur_param_p
,
858 struct iscsi_param
**params_dst_p
,
859 struct iscsi_param
*param
)
863 *cur_param_p
= spdk_iscsi_param_find(*params_dst_p
, param
->key
);
864 if (*cur_param_p
== NULL
) {
865 *params_dst_p
= conn
->sess
->params
;
866 *cur_param_p
= spdk_iscsi_param_find(*params_dst_p
, param
->key
);
867 if (*cur_param_p
== NULL
) {
868 if ((strncasecmp(param
->key
, "X-", 2) == 0) ||
869 (strncasecmp(param
->key
, "X#", 2) == 0)) {
871 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
,
872 "extension key %.64s\n",
875 SPDK_ERRLOG("unknown key %.64s\n", param
->key
);
879 index
= (*cur_param_p
)->state_index
;
880 if (conn
->sess_param_state_negotiated
[index
] &&
881 !iscsi_find_key_in_array(param
->key
,
882 target_declarative_params
)) {
883 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE
;
885 conn
->sess_param_state_negotiated
[index
] = true;
888 index
= (*cur_param_p
)->state_index
;
889 if (conn
->conn_param_state_negotiated
[index
] &&
890 !iscsi_find_key_in_array(param
->key
,
891 multi_negot_conn_params
)) {
892 return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE
;
894 conn
->conn_param_state_negotiated
[index
] = true;
901 spdk_iscsi_negotiate_params(struct spdk_iscsi_conn
*conn
,
902 struct iscsi_param
**params
, uint8_t *data
, int alloc_len
,
905 struct iscsi_param
*param
;
906 struct iscsi_param
*cur_param
;
907 char *valid_list
, *in_val
;
913 uint32_t FirstBurstLength
;
914 uint32_t MaxBurstLength
;
915 bool FirstBurstLength_flag
= false;
926 if (total
> alloc_len
) {
928 data
[total
- 1] = '\0';
932 if (*params
== NULL
) {
939 cur_param
= spdk_iscsi_param_find(*params
, "SessionType");
940 if (cur_param
== NULL
) {
941 cur_param
= spdk_iscsi_param_find(conn
->sess
->params
, "SessionType");
942 if (cur_param
== NULL
) {
943 /* no session type */
945 if (strcasecmp(cur_param
->val
, "Discovery") == 0) {
950 if (strcasecmp(cur_param
->val
, "Discovery") == 0) {
955 /* for temporary store */
956 valid_list
= malloc(ISCSI_TEXT_MAX_VAL_LEN
+ 1);
958 SPDK_ERRLOG("malloc() failed for valid_list\n");
962 in_val
= malloc(ISCSI_TEXT_MAX_VAL_LEN
+ 1);
964 SPDK_ERRLOG("malloc() failed for in_val\n");
969 cur_val
= malloc(ISCSI_TEXT_MAX_VAL_LEN
+ 1);
971 SPDK_ERRLOG("malloc() failed for cur_val\n");
977 /* To adjust the location of FirstBurstLength location and put it to
978 * the end, then we can always firstly determine the MaxBurstLength
980 param
= spdk_iscsi_param_find(*params
, "MaxBurstLength");
982 param
= spdk_iscsi_param_find(*params
, "FirstBurstLength");
984 /* check the existence of FirstBurstLength */
986 FirstBurstLength_flag
= true;
987 if (param
->next
!= NULL
) {
988 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", param
->val
);
990 spdk_iscsi_param_add(params
, "FirstBurstLength",
996 for (param
= *params
; param
!= NULL
; param
= param
->next
) {
997 struct iscsi_param
*params_dst
= conn
->params
;
998 int add_param_value
= 0;
1000 param
->type
= ISPT_INVALID
;
1002 /* sendtargets is special */
1003 if (strcasecmp(param
->key
, "SendTargets") == 0) {
1007 if (iscsi_find_key_in_array(param
->key
, chap_type
)) {
1011 /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */
1013 iscsi_find_key_in_array(param
->key
, discovery_ignored_param
)) {
1014 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", "Irrelevant");
1016 add_param_value
= 1;
1018 rc
= iscsi_negotiate_param_init(conn
,
1027 } else if (rc
> 0) {
1028 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", "NotUnderstood");
1030 add_param_value
= 1;
1032 snprintf(valid_list
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", cur_param
->list
);
1033 snprintf(cur_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", cur_param
->val
);
1034 param
->type
= cur_param
->type
;
1038 if (param
->type
> 0) {
1039 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
+ 1, "%s", param
->val
);
1041 /* "NotUnderstood" value shouldn't be assigned to "Understood" key */
1042 if (strcasecmp(in_val
, "NotUnderstood") == 0) {
1046 return SPDK_ISCSI_LOGIN_ERROR_PARAMETER
;
1049 if (strcasecmp(param
->key
, "FirstBurstLength") == 0) {
1050 FirstBurstLength
= (uint32_t)strtol(param
->val
, NULL
,
1052 new_val
= spdk_iscsi_param_get_val(conn
->sess
->params
,
1054 if (new_val
!= NULL
) {
1055 MaxBurstLength
= (uint32_t) strtol(new_val
, NULL
,
1058 MaxBurstLength
= SPDK_ISCSI_MAX_BURST_LENGTH
;
1060 if (FirstBurstLength
< SPDK_ISCSI_MAX_FIRST_BURST_LENGTH
&&
1061 FirstBurstLength
> MaxBurstLength
) {
1062 FirstBurstLength
= MaxBurstLength
;
1063 snprintf(in_val
, ISCSI_TEXT_MAX_VAL_LEN
, "%d",
1068 /* prevent target's declarative params from being changed by initiator */
1069 if (iscsi_find_key_in_array(param
->key
, target_declarative_params
)) {
1070 add_param_value
= 1;
1073 new_val
= iscsi_negotiate_param_all(&add_param_value
,
1080 /* check the negotiated value of the key */
1081 if (new_val
!= NULL
) {
1082 /* add_param_value = 0 means updating the value of
1083 * existed key in the connection's parameters
1085 if (add_param_value
== 0) {
1086 spdk_iscsi_param_set(params_dst
, param
->key
, new_val
);
1088 total
= iscsi_construct_data_from_param(param
,
1097 total
= iscsi_special_param_construction(conn
,
1099 FirstBurstLength_flag
,
1121 spdk_iscsi_copy_param2var(struct spdk_iscsi_conn
*conn
)
1125 val
= spdk_iscsi_param_get_val(conn
->params
, "MaxRecvDataSegmentLength");
1127 SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n");
1130 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
,
1131 "copy MaxRecvDataSegmentLength=%s\n", val
);
1132 conn
->MaxRecvDataSegmentLength
= (int)strtol(val
, NULL
, 10);
1133 if (conn
->MaxRecvDataSegmentLength
> SPDK_BDEV_LARGE_BUF_MAX_SIZE
) {
1134 conn
->MaxRecvDataSegmentLength
= SPDK_BDEV_LARGE_BUF_MAX_SIZE
;
1137 val
= spdk_iscsi_param_get_val(conn
->params
, "HeaderDigest");
1139 SPDK_ERRLOG("Getval HeaderDigest failed\n");
1142 if (strcasecmp(val
, "CRC32C") == 0) {
1143 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set HeaderDigest=1\n");
1144 conn
->header_digest
= 1;
1146 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set HeaderDigest=0\n");
1147 conn
->header_digest
= 0;
1149 val
= spdk_iscsi_param_get_val(conn
->params
, "DataDigest");
1151 SPDK_ERRLOG("Getval DataDigest failed\n");
1154 if (strcasecmp(val
, "CRC32C") == 0) {
1155 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set DataDigest=1\n");
1156 conn
->data_digest
= 1;
1158 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set DataDigest=0\n");
1159 conn
->data_digest
= 0;
1162 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "MaxConnections");
1164 SPDK_ERRLOG("Getval MaxConnections failed\n");
1167 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "copy MaxConnections=%s\n", val
);
1168 conn
->sess
->MaxConnections
= (uint32_t) strtol(val
, NULL
, 10);
1169 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "MaxOutstandingR2T");
1171 SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n");
1174 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "copy MaxOutstandingR2T=%s\n", val
);
1175 conn
->sess
->MaxOutstandingR2T
= (uint32_t) strtol(val
, NULL
, 10);
1176 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "FirstBurstLength");
1178 SPDK_ERRLOG("Getval FirstBurstLength failed\n");
1181 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "copy FirstBurstLength=%s\n", val
);
1182 conn
->sess
->FirstBurstLength
= (uint32_t) strtol(val
, NULL
, 10);
1183 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "MaxBurstLength");
1185 SPDK_ERRLOG("Getval MaxBurstLength failed\n");
1188 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "copy MaxBurstLength=%s\n", val
);
1189 conn
->sess
->MaxBurstLength
= (uint32_t) strtol(val
, NULL
, 10);
1190 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "InitialR2T");
1192 SPDK_ERRLOG("Getval InitialR2T failed\n");
1195 if (strcasecmp(val
, "Yes") == 0) {
1196 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set InitialR2T=1\n");
1197 conn
->sess
->InitialR2T
= true;
1199 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set InitialR2T=0\n");
1200 conn
->sess
->InitialR2T
= false;
1202 val
= spdk_iscsi_param_get_val(conn
->sess
->params
, "ImmediateData");
1204 SPDK_ERRLOG("Getval ImmediateData failed\n");
1207 if (strcasecmp(val
, "Yes") == 0) {
1208 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set ImmediateData=1\n");
1209 conn
->sess
->ImmediateData
= true;
1211 SPDK_DEBUGLOG(SPDK_LOG_ISCSI
, "set ImmediateData=0\n");
1212 conn
->sess
->ImmediateData
= false;