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