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