xref: /spdk/lib/iscsi/param.c (revision a83f91c29a4740e4bea5f9509b7036e9e7dc2788)
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 		p = spdk_sprintf_alloc("%s%s", *partial_parameter, (const char *)data);
312 		if (!p) {
313 			return -1;
314 		}
315 		rc = spdk_iscsi_parse_param(params, p);
316 		free(p);
317 		if (rc < 0) {
318 			return -1;
319 		}
320 		free(*partial_parameter);
321 		*partial_parameter = NULL;
322 
323 		data = data + i + 1;
324 		len = len - (i + 1);
325 	}
326 
327 	/* strip the partial text parameters if C bit is enabled */
328 	if (cbit_enabled) {
329 		if (partial_parameter == NULL) {
330 			SPDK_ERRLOG("C bit set but no partial parameters provided\n");
331 			return -1;
332 		}
333 
334 		/*
335 		 * reverse iterate the string from the tail not including '\0'
336 		 * index of last '\0' is len -1.
337 		 */
338 		for (i = len - 2; data[i] != '\0' && i > 0; i--)
339 			;
340 		*partial_parameter = xstrdup(&data[i == 0 ? 0 : i + 1]);
341 		len = (i == 0 ? 0 : i + 1);
342 	}
343 
344 	while (offset < len && data[offset] != '\0') {
345 		rc = spdk_iscsi_parse_param(params, data + offset);
346 		if (rc < 0) {
347 			return -1;
348 		}
349 		offset += rc;
350 	}
351 	return 0;
352 }
353 
354 char *
355 spdk_iscsi_param_get_val(struct iscsi_param *params, const char *key)
356 {
357 	struct iscsi_param *param;
358 
359 	param = spdk_iscsi_param_find(params, key);
360 	if (param == NULL) {
361 		return NULL;
362 	}
363 	return param->val;
364 }
365 
366 int
367 spdk_iscsi_param_eq_val(struct iscsi_param *params, const char *key,
368 			const char *val)
369 {
370 	struct iscsi_param *param;
371 
372 	param = spdk_iscsi_param_find(params, key);
373 	if (param == NULL) {
374 		return 0;
375 	}
376 	if (strcasecmp(param->val, val) == 0) {
377 		return 1;
378 	}
379 	return 0;
380 }
381 
382 struct iscsi_param_table {
383 	const char *key;
384 	const char *val;
385 	const char *list;
386 	int type;
387 };
388 
389 static const struct iscsi_param_table conn_param_table[] = {
390 	{ "HeaderDigest", "None", "CRC32C,None", ISPT_LIST },
391 	{ "DataDigest", "None", "CRC32C,None", ISPT_LIST },
392 	{ "MaxRecvDataSegmentLength", "8192", "512,16777215", ISPT_NUMERICAL_DECLARATIVE },
393 	{ "OFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
394 	{ "IFMarker", "No", "Yes,No", ISPT_BOOLEAN_AND },
395 	{ "OFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN },
396 	{ "IFMarkInt", "1", "1,65535", ISPT_NUMERICAL_MIN },
397 	{ "AuthMethod", "None", "CHAP,None", ISPT_LIST },
398 	{ "CHAP_A", "5", "5", ISPT_LIST },
399 	{ "CHAP_N", "", "", ISPT_DECLARATIVE },
400 	{ "CHAP_R", "", "", ISPT_DECLARATIVE },
401 	{ "CHAP_I", "", "", ISPT_DECLARATIVE },
402 	{ "CHAP_C", "", "", ISPT_DECLARATIVE },
403 	{ NULL, NULL, NULL, ISPT_INVALID },
404 };
405 
406 static const struct iscsi_param_table sess_param_table[] = {
407 	{ "MaxConnections", "1", "1,65535", ISPT_NUMERICAL_MIN },
408 #if 0
409 	/* need special handling */
410 	{ "SendTargets", "", "", ISPT_DECLARATIVE },
411 #endif
412 	{ "TargetName", "", "", ISPT_DECLARATIVE },
413 	{ "InitiatorName", "", "", ISPT_DECLARATIVE },
414 	{ "TargetAlias", "", "", ISPT_DECLARATIVE },
415 	{ "InitiatorAlias", "", "", ISPT_DECLARATIVE },
416 	{ "TargetAddress", "", "", ISPT_DECLARATIVE },
417 	{ "TargetPortalGroupTag", "1", "1,65535", ISPT_NUMERICAL_DECLARATIVE },
418 	{ "InitialR2T", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
419 	{ "ImmediateData", "Yes", "Yes,No", ISPT_BOOLEAN_AND },
420 	{ "MaxBurstLength", "262144", "512,16777215", ISPT_NUMERICAL_MIN },
421 	{ "FirstBurstLength", "65536", "512,16777215", ISPT_NUMERICAL_MIN },
422 	{ "DefaultTime2Wait", "2", "0,3600", ISPT_NUMERICAL_MAX },
423 	{ "DefaultTime2Retain", "20", "0,3600", ISPT_NUMERICAL_MIN },
424 	{ "MaxOutstandingR2T", "1", "1,65536", ISPT_NUMERICAL_MIN },
425 	{ "DataPDUInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
426 	{ "DataSequenceInOrder", "Yes", "Yes,No", ISPT_BOOLEAN_OR },
427 	{ "ErrorRecoveryLevel", "0", "0,2", ISPT_NUMERICAL_MIN },
428 	{ "SessionType", "Normal", "Normal,Discovery", ISPT_DECLARATIVE },
429 	{ NULL, NULL, NULL, ISPT_INVALID },
430 };
431 
432 static int
433 spdk_iscsi_params_init_internal(struct iscsi_param **params,
434 				const struct iscsi_param_table *table)
435 {
436 	int rc;
437 	int i;
438 	struct iscsi_param *param;
439 
440 	for (i = 0; table[i].key != NULL; i++) {
441 		rc = spdk_iscsi_param_add(params, table[i].key, table[i].val,
442 					  table[i].list, table[i].type);
443 		if (rc < 0) {
444 			SPDK_ERRLOG("iscsi_param_add() failed\n");
445 			return -1;
446 		}
447 		param = spdk_iscsi_param_find(*params, table[i].key);
448 		if (param != NULL) {
449 			param->state_index = i;
450 		} else {
451 			SPDK_ERRLOG("spdk_iscsi_param_find() failed\n");
452 			return -1;
453 		}
454 	}
455 
456 	return 0;
457 }
458 
459 int
460 spdk_iscsi_conn_params_init(struct iscsi_param **params)
461 {
462 	return spdk_iscsi_params_init_internal(params, &conn_param_table[0]);
463 }
464 
465 int
466 spdk_iscsi_sess_params_init(struct iscsi_param **params)
467 {
468 	return spdk_iscsi_params_init_internal(params, &sess_param_table[0]);
469 }
470 
471 static const char *chap_type[] = {
472 	"CHAP_A",
473 	"CHAP_N",
474 	"CHAP_R",
475 	"CHAP_I",
476 	"CHAP_C",
477 	NULL,
478 };
479 
480 static const char *discovery_ignored_param[] = {
481 	"MaxConnections",
482 	"InitialR2T",
483 	"ImmediateData",
484 	"MaxBurstLength",
485 	"FirstBurstLength"
486 	"MaxOutstandingR2T",
487 	"DataPDUInOrder",
488 	NULL,
489 };
490 
491 static const char *multi_negot_conn_params[] = {
492 	"MaxRecvDataSegmentLength",
493 	NULL,
494 };
495 
496 /* The following params should be declared by target */
497 static const char *target_declarative_params[] = {
498 	"TargetAlias",
499 	"TargetAddress",
500 	"TargetPortalGroupTag",
501 	NULL,
502 };
503 
504 /* This function is used to contruct the data from the special param (e.g.,
505  * MaxRecvDataSegmentLength)
506  * return:
507  * normal: the total len of the data
508  * error: -1
509  */
510 static int
511 spdk_iscsi_special_param_construction(struct spdk_iscsi_conn *conn,
512 				      struct iscsi_param *param,
513 				      bool FirstBurstLength_flag, char *data,
514 				      int alloc_len, int total)
515 {
516 	int len;
517 	struct iscsi_param *param_first;
518 	struct iscsi_param *param_max;
519 	uint32_t FirstBurstLength;
520 	uint32_t MaxBurstLength;
521 	char *val;
522 
523 	val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
524 	if (!val) {
525 		SPDK_ERRLOG("malloc() failed for temporary buffer\n");
526 		return -ENOMEM;
527 	}
528 
529 	if (strcasecmp(param->key, "MaxRecvDataSegmentLength") == 0) {
530 		/*
531 		 * MaxRecvDataSegmentLength is sent by both
532 		 *      initiator and target, but is declarative - meaning
533 		 *      each direction can have different values.
534 		 * So when MaxRecvDataSegmentLength is found in the
535 		 *      the parameter set sent from the initiator, add SPDK
536 		 *      iscsi target's MaxRecvDataSegmentLength value to
537 		 *      the returned parameter list.
538 		 */
539 		if (alloc_len - total < 1) {
540 			SPDK_ERRLOG("data space small %d\n", alloc_len);
541 			free(val);
542 			return -1;
543 		}
544 
545 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
546 			      "returning MaxRecvDataSegmentLength=%d\n",
547 			      SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
548 		len = snprintf((char *)data + total, alloc_len - total,
549 			       "MaxRecvDataSegmentLength=%d",
550 			       SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
551 		total += len + 1;
552 	}
553 
554 	if (strcasecmp(param->key, "MaxBurstLength") == 0 &&
555 	    !FirstBurstLength_flag) {
556 		if (alloc_len - total < 1) {
557 			SPDK_ERRLOG("data space small %d\n", alloc_len);
558 			free(val);
559 			return -1;
560 		}
561 
562 		param_first = spdk_iscsi_param_find(conn->sess->params,
563 						    "FirstBurstLength");
564 		if (param_first != NULL) {
565 			FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10);
566 		} else {
567 			FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
568 		}
569 		param_max = spdk_iscsi_param_find(conn->sess->params,
570 						  "MaxBurstLength");
571 		if (param_max != NULL) {
572 			MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10);
573 		} else {
574 			MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
575 		}
576 
577 		if (FirstBurstLength > MaxBurstLength) {
578 			FirstBurstLength = MaxBurstLength;
579 			if (param_first != NULL) {
580 				free(param_first->val);
581 				snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
582 					 FirstBurstLength);
583 				param_first->val = xstrdup(val);
584 			}
585 		}
586 		len = snprintf((char *)data + total, alloc_len - total,
587 			       "FirstBurstLength=%d", FirstBurstLength);
588 		total += len + 1;
589 	}
590 
591 	free(val);
592 	return total;
593 
594 }
595 
596 /**
597  * spdk_iscsi_construct_data_from_param:
598  * To construct the data which will be returned to the initiator
599  * return: length of the negotiated data, -1 inidicates error;
600  */
601 static int
602 spdk_iscsi_construct_data_from_param(struct iscsi_param *param, char *new_val,
603 				     char *data, int alloc_len, int total)
604 
605 {
606 	int len;
607 
608 	if (param->type != ISPT_DECLARATIVE &&
609 	    param->type != ISPT_NUMERICAL_DECLARATIVE) {
610 		if (alloc_len - total < 1) {
611 			SPDK_ERRLOG("data space small %d\n", alloc_len);
612 			return -1;
613 		}
614 
615 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "negotiated %s=%s\n",
616 			      param->key, new_val);
617 		len = snprintf((char *)data + total, alloc_len - total, "%s=%s",
618 			       param->key, new_val);
619 		total += len + 1;
620 	}
621 	return total;
622 
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,
1054 						     new_val);
1055 
1056 			total = spdk_iscsi_construct_data_from_param(param,
1057 					new_val,
1058 					data,
1059 					alloc_len,
1060 					total);
1061 			if (total < 0) {
1062 				goto final_return;
1063 			}
1064 
1065 			total = spdk_iscsi_special_param_construction(conn,
1066 					param,
1067 					FirstBurstLength_flag,
1068 					data,
1069 					alloc_len,
1070 					total);
1071 			if (total < 0) {
1072 				goto final_return;
1073 			}
1074 		} else {
1075 			total = -1;
1076 			break;
1077 		}
1078 	}
1079 
1080 final_return:
1081 	free(valid_list);
1082 	free(in_val);
1083 	free(cur_val);
1084 
1085 	return total;
1086 }
1087 
1088 int
1089 spdk_iscsi_copy_param2var(struct spdk_iscsi_conn *conn)
1090 {
1091 	const char *val;
1092 
1093 	val = spdk_iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength");
1094 	if (val == NULL) {
1095 		SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n");
1096 		return -1;
1097 	}
1098 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI,
1099 		      "copy MaxRecvDataSegmentLength=%s\n", val);
1100 	conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10);
1101 	if (conn->MaxRecvDataSegmentLength > SPDK_ISCSI_MAX_SEND_DATA_SEGMENT_LENGTH) {
1102 		conn->MaxRecvDataSegmentLength = SPDK_ISCSI_MAX_SEND_DATA_SEGMENT_LENGTH;
1103 	}
1104 
1105 	val = spdk_iscsi_param_get_val(conn->params, "HeaderDigest");
1106 	if (val == NULL) {
1107 		SPDK_ERRLOG("Getval HeaderDigest failed\n");
1108 		return -1;
1109 	}
1110 	if (strcasecmp(val, "CRC32C") == 0) {
1111 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=1\n");
1112 		conn->header_digest = 1;
1113 	} else {
1114 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set HeaderDigest=0\n");
1115 		conn->header_digest = 0;
1116 	}
1117 	val = spdk_iscsi_param_get_val(conn->params, "DataDigest");
1118 	if (val == NULL) {
1119 		SPDK_ERRLOG("Getval DataDigest failed\n");
1120 		return -1;
1121 	}
1122 	if (strcasecmp(val, "CRC32C") == 0) {
1123 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=1\n");
1124 		conn->data_digest = 1;
1125 	} else {
1126 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set DataDigest=0\n");
1127 		conn->data_digest = 0;
1128 	}
1129 
1130 	val = spdk_iscsi_param_get_val(conn->sess->params, "MaxConnections");
1131 	if (val == NULL) {
1132 		SPDK_ERRLOG("Getval MaxConnections failed\n");
1133 		return -1;
1134 	}
1135 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxConnections=%s\n", val);
1136 	conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10);
1137 	val = spdk_iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T");
1138 	if (val == NULL) {
1139 		SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n");
1140 		return -1;
1141 	}
1142 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxOutstandingR2T=%s\n", val);
1143 	conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10);
1144 	val = spdk_iscsi_param_get_val(conn->sess->params, "FirstBurstLength");
1145 	if (val == NULL) {
1146 		SPDK_ERRLOG("Getval FirstBurstLength failed\n");
1147 		return -1;
1148 	}
1149 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy FirstBurstLength=%s\n", val);
1150 	conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10);
1151 	val = spdk_iscsi_param_get_val(conn->sess->params, "MaxBurstLength");
1152 	if (val == NULL) {
1153 		SPDK_ERRLOG("Getval MaxBurstLength failed\n");
1154 		return -1;
1155 	}
1156 	SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "copy MaxBurstLength=%s\n", val);
1157 	conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10);
1158 	val = spdk_iscsi_param_get_val(conn->sess->params, "InitialR2T");
1159 	if (val == NULL) {
1160 		SPDK_ERRLOG("Getval InitialR2T failed\n");
1161 		return -1;
1162 	}
1163 	if (strcasecmp(val, "Yes") == 0) {
1164 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=1\n");
1165 		conn->sess->InitialR2T = true;
1166 	} else {
1167 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set InitialR2T=0\n");
1168 		conn->sess->InitialR2T = false;
1169 	}
1170 	val = spdk_iscsi_param_get_val(conn->sess->params, "ImmediateData");
1171 	if (val == NULL) {
1172 		SPDK_ERRLOG("Getval ImmediateData failed\n");
1173 		return -1;
1174 	}
1175 	if (strcasecmp(val, "Yes") == 0) {
1176 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=1\n");
1177 		conn->sess->ImmediateData = true;
1178 	} else {
1179 		SPDK_DEBUGLOG(SPDK_LOG_ISCSI, "set ImmediateData=0\n");
1180 		conn->sess->ImmediateData = false;
1181 	}
1182 	return 0;
1183 }
1184