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