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