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