]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/lib/iscsi/param.c
e09bf899a6fab1c8bb00f7119adbb6e6dec48f18
[ceph.git] / ceph / src / spdk / lib / iscsi / param.c
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 construct 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 indicates 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 }