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