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