Line data Source code
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
26 30 : iscsi_param_free(struct iscsi_param *params)
27 : {
28 : struct iscsi_param *param, *next_param;
29 :
30 30 : if (params == NULL) {
31 4 : return;
32 : }
33 251 : for (param = params; param != NULL; param = next_param) {
34 225 : next_param = param->next;
35 225 : if (param->list) {
36 186 : free(param->list);
37 186 : }
38 225 : free(param->val);
39 225 : free(param->key);
40 225 : free(param);
41 225 : }
42 30 : }
43 :
44 : static int
45 71 : iscsi_find_key_in_array(const char *key, const char *array[])
46 : {
47 : int i;
48 :
49 281 : for (i = 0; array[i] != NULL; i++) {
50 212 : if (strcasecmp(key, array[i]) == 0) {
51 2 : return 1;
52 : }
53 210 : }
54 69 : return 0;
55 71 : }
56 :
57 : struct iscsi_param *
58 631 : iscsi_param_find(struct iscsi_param *params, const char *key)
59 : {
60 : struct iscsi_param *param;
61 :
62 631 : if (params == NULL || key == NULL) {
63 32 : return NULL;
64 : }
65 4795 : for (param = params; param != NULL; param = param->next) {
66 4534 : if (param->key != NULL && param->key[0] == key[0]
67 4533 : && strcasecmp(param->key, key) == 0) {
68 338 : return param;
69 : }
70 4196 : }
71 261 : return NULL;
72 631 : }
73 :
74 : int
75 6 : iscsi_param_del(struct iscsi_param **params, const char *key)
76 : {
77 6 : struct iscsi_param *param, *prev_param = NULL;
78 :
79 6 : SPDK_DEBUGLOG(iscsi, "del %s\n", key);
80 6 : if (params == NULL || key == NULL) {
81 0 : return 0;
82 : }
83 6 : for (param = *params; param != NULL; param = param->next) {
84 6 : if (param->key != NULL && param->key[0] == key[0]
85 6 : && strcasecmp(param->key, key) == 0) {
86 6 : if (prev_param != NULL) {
87 0 : prev_param->next = param->next;
88 0 : } else {
89 6 : *params = param->next;
90 : }
91 6 : param->next = NULL;
92 6 : iscsi_param_free(param);
93 6 : return 0;
94 : }
95 0 : prev_param = param;
96 0 : }
97 0 : return -1;
98 6 : }
99 :
100 : int
101 225 : 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 225 : SPDK_DEBUGLOG(iscsi, "add %s=%s, list=[%s], type=%d\n",
107 : key, val, list, type);
108 225 : if (key == NULL) {
109 0 : return -1;
110 : }
111 :
112 225 : param = iscsi_param_find(*params, key);
113 225 : if (param != NULL) {
114 6 : iscsi_param_del(params, key);
115 6 : }
116 :
117 225 : param = calloc(1, sizeof(*param));
118 225 : if (!param) {
119 0 : SPDK_ERRLOG("calloc() failed for parameter\n");
120 0 : return -ENOMEM;
121 : }
122 :
123 225 : param->next = NULL;
124 225 : param->key = xstrdup(key);
125 225 : param->val = xstrdup(val);
126 225 : param->list = xstrdup(list);
127 225 : param->type = type;
128 :
129 225 : last_param = *params;
130 225 : if (last_param != NULL) {
131 1485 : while (last_param->next != NULL) {
132 1280 : last_param = last_param->next;
133 : }
134 205 : last_param->next = param;
135 205 : } else {
136 20 : *params = param;
137 : }
138 :
139 225 : return 0;
140 225 : }
141 :
142 : int
143 18 : iscsi_param_set(struct iscsi_param *params, const char *key,
144 : const char *val)
145 : {
146 : struct iscsi_param *param;
147 :
148 18 : SPDK_DEBUGLOG(iscsi, "set %s=%s\n", key, val);
149 18 : param = iscsi_param_find(params, key);
150 18 : if (param == NULL) {
151 0 : SPDK_ERRLOG("no key %s\n", key);
152 0 : return -1;
153 : }
154 :
155 18 : free(param->val);
156 :
157 18 : param->val = xstrdup(val);
158 :
159 18 : return 0;
160 18 : }
161 :
162 : int
163 12 : 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 12 : SPDK_DEBUGLOG(iscsi, "set %s=%d\n", key, val);
169 12 : param = iscsi_param_find(params, key);
170 12 : if (param == NULL) {
171 0 : SPDK_ERRLOG("no key %s\n", key);
172 0 : return -1;
173 : }
174 :
175 12 : free(param->val);
176 12 : snprintf(buf, sizeof buf, "%d", val);
177 :
178 12 : param->val = strdup(buf);
179 :
180 12 : return 0;
181 12 : }
182 :
183 : /**
184 : * Parse a single KEY=VAL pair
185 : *
186 : * data = "KEY=VAL<NUL>"
187 : */
188 : static int
189 40 : 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 40 : data_len = strnlen(data, data_len);
198 : /* No such thing as strnchr so use memchr instead. */
199 40 : key_end = memchr(data, '=', data_len);
200 40 : if (!key_end) {
201 2 : SPDK_ERRLOG("'=' not found\n");
202 2 : return -1;
203 : }
204 :
205 38 : key_len = key_end - data;
206 38 : if (key_len == 0) {
207 1 : SPDK_ERRLOG("Empty key\n");
208 1 : return -1;
209 : }
210 : /*
211 : * RFC 7143 6.1
212 : */
213 37 : if (key_len > ISCSI_TEXT_MAX_KEY_LEN) {
214 1 : SPDK_ERRLOG("Key name length is bigger than 63\n");
215 1 : return -1;
216 : }
217 :
218 36 : key_copy = malloc(key_len + 1);
219 36 : if (!key_copy) {
220 0 : SPDK_ERRLOG("malloc() failed for key_copy\n");
221 0 : return -ENOMEM;
222 : }
223 :
224 36 : memcpy(key_copy, data, key_len);
225 36 : key_copy[key_len] = '\0';
226 : /* check whether this key is duplicated */
227 36 : if (NULL != iscsi_param_find(*params, key_copy)) {
228 1 : SPDK_ERRLOG("Duplicated Key %s\n", key_copy);
229 1 : free(key_copy);
230 1 : return -1;
231 : }
232 :
233 35 : 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 35 : 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 35 : if (val_len > max_len) {
247 2 : SPDK_ERRLOG("Overflow Val %d\n", val_len);
248 2 : free(key_copy);
249 2 : return -1;
250 : }
251 :
252 33 : val_copy = calloc(1, val_len + 1);
253 33 : if (val_copy == NULL) {
254 0 : SPDK_ERRLOG("Could not allocate value string\n");
255 0 : free(key_copy);
256 0 : return -1;
257 : }
258 :
259 33 : memcpy(val_copy, key_end + 1, val_len);
260 :
261 33 : rc = iscsi_param_add(params, key_copy, val_copy, NULL, 0);
262 33 : free(val_copy);
263 33 : free(key_copy);
264 33 : if (rc < 0) {
265 0 : SPDK_ERRLOG("iscsi_param_add() failed\n");
266 0 : return -1;
267 : }
268 :
269 : /* return number of bytes consumed
270 : * +1 for '=' and +1 for NUL
271 : */
272 33 : return key_len + 1 + val_len + 1;
273 40 : }
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
284 29 : iscsi_parse_params(struct iscsi_param **params, const uint8_t *data,
285 : int len, bool cbit_enabled, char **partial_parameter)
286 : {
287 29 : 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 29 : if (len == 0) {
296 2 : return 0;
297 : }
298 :
299 27 : assert(data != NULL);
300 :
301 : /* strip the partial text parameters if previous PDU have C enabled */
302 27 : if (partial_parameter && *partial_parameter) {
303 34 : for (i = 0; i < len && data[i] != '\0'; i++) {
304 : ;
305 30 : }
306 4 : p = spdk_sprintf_alloc("%s%s", *partial_parameter, (const char *)data);
307 4 : if (!p) {
308 0 : return -1;
309 : }
310 4 : rc = iscsi_parse_param(params, p, i + strlen(*partial_parameter));
311 4 : free(p);
312 4 : if (rc < 0) {
313 0 : return -1;
314 : }
315 4 : free(*partial_parameter);
316 4 : *partial_parameter = NULL;
317 :
318 4 : data = data + i + 1;
319 4 : len = len - (i + 1);
320 4 : }
321 :
322 : /* strip the partial text parameters if C bit is enabled */
323 27 : if (cbit_enabled) {
324 4 : if (partial_parameter == NULL) {
325 0 : SPDK_ERRLOG("C bit set but no partial parameters provided\n");
326 0 : return -1;
327 : }
328 :
329 : /*
330 : * reverse iterate the string from the tail not including '\0'
331 : */
332 22 : for (i = len - 1; data[i] != '\0' && i > 0; i--) {
333 : ;
334 18 : }
335 4 : if (i != 0) {
336 : /* We found a NULL character - don't copy it into the
337 : * partial parameter.
338 : */
339 1 : i++;
340 1 : }
341 :
342 4 : *partial_parameter = calloc(1, len - i + 1);
343 4 : if (*partial_parameter == NULL) {
344 0 : SPDK_ERRLOG("could not allocate partial parameter\n");
345 0 : return -1;
346 : }
347 4 : memcpy(*partial_parameter, &data[i], len - i);
348 4 : if (i == 0) {
349 : /* No full parameters to parse - so return now. */
350 3 : return 0;
351 : } else {
352 1 : len = i - 1;
353 : }
354 1 : }
355 :
356 53 : while (offset < len && data[offset] != '\0') {
357 36 : rc = iscsi_parse_param(params, data + offset, len - offset);
358 36 : if (rc < 0) {
359 7 : return -1;
360 : }
361 29 : offset += rc;
362 : }
363 17 : return 0;
364 29 : }
365 :
366 : char *
367 93 : iscsi_param_get_val(struct iscsi_param *params, const char *key)
368 : {
369 : struct iscsi_param *param;
370 :
371 93 : param = iscsi_param_find(params, key);
372 93 : if (param == NULL) {
373 14 : return NULL;
374 : }
375 79 : return param->val;
376 93 : }
377 :
378 : int
379 1 : iscsi_param_eq_val(struct iscsi_param *params, const char *key,
380 : const char *val)
381 : {
382 : struct iscsi_param *param;
383 :
384 1 : param = iscsi_param_find(params, key);
385 1 : if (param == NULL) {
386 1 : return 0;
387 : }
388 0 : if (strcasecmp(param->val, val) == 0) {
389 0 : return 1;
390 : }
391 0 : return 0;
392 1 : }
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
445 12 : 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 198 : for (i = 0; table[i].key != NULL; i++) {
453 372 : rc = iscsi_param_add(params, table[i].key, table[i].val,
454 186 : table[i].list, table[i].type);
455 186 : if (rc < 0) {
456 0 : SPDK_ERRLOG("iscsi_param_add() failed\n");
457 0 : return -1;
458 : }
459 186 : param = iscsi_param_find(*params, table[i].key);
460 186 : if (param != NULL) {
461 186 : param->state_index = i;
462 186 : } else {
463 0 : SPDK_ERRLOG("iscsi_param_find() failed\n");
464 0 : return -1;
465 : }
466 186 : }
467 :
468 12 : return 0;
469 12 : }
470 :
471 : int
472 6 : iscsi_conn_params_init(struct iscsi_param **params)
473 : {
474 6 : return iscsi_params_init_internal(params, &conn_param_table[0]);
475 : }
476 :
477 : int
478 6 : iscsi_sess_params_init(struct iscsi_param **params)
479 : {
480 6 : 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
524 18 : 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 18 : val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
537 18 : if (!val) {
538 0 : SPDK_ERRLOG("malloc() failed for temporary buffer\n");
539 0 : return -ENOMEM;
540 : }
541 :
542 18 : 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 0 : if (alloc_len - total < 1) {
553 0 : SPDK_ERRLOG("data space small %d\n", alloc_len);
554 0 : free(val);
555 0 : return -1;
556 : }
557 :
558 0 : SPDK_DEBUGLOG(iscsi,
559 : "returning MaxRecvDataSegmentLength=%d\n",
560 : SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
561 0 : len = snprintf((char *)data + total, alloc_len - total,
562 : "MaxRecvDataSegmentLength=%d",
563 : SPDK_ISCSI_MAX_RECV_DATA_SEGMENT_LENGTH);
564 0 : total += len + 1;
565 0 : }
566 :
567 18 : if (strcasecmp(param->key, "MaxBurstLength") == 0 &&
568 6 : !FirstBurstLength_flag) {
569 0 : if (alloc_len - total < 1) {
570 0 : SPDK_ERRLOG("data space small %d\n", alloc_len);
571 0 : free(val);
572 0 : return -1;
573 : }
574 :
575 0 : param_first = iscsi_param_find(conn->sess->params,
576 : "FirstBurstLength");
577 0 : if (param_first != NULL) {
578 0 : FirstBurstLength = (uint32_t)strtol(param_first->val, NULL, 10);
579 0 : } else {
580 0 : FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
581 : }
582 0 : param_max = iscsi_param_find(conn->sess->params,
583 : "MaxBurstLength");
584 0 : if (param_max != NULL) {
585 0 : MaxBurstLength = (uint32_t)strtol(param_max->val, NULL, 10);
586 0 : } else {
587 0 : MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
588 : }
589 :
590 0 : if (FirstBurstLength > MaxBurstLength) {
591 0 : FirstBurstLength = MaxBurstLength;
592 0 : if (param_first != NULL) {
593 0 : free(param_first->val);
594 0 : snprintf(val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
595 0 : FirstBurstLength);
596 0 : param_first->val = xstrdup(val);
597 0 : }
598 0 : }
599 0 : len = snprintf((char *)data + total, alloc_len - total,
600 0 : "FirstBurstLength=%d", FirstBurstLength);
601 0 : total += len + 1;
602 0 : }
603 :
604 18 : free(val);
605 18 : return total;
606 :
607 18 : }
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
615 18 : 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 18 : if (param->type != ISPT_DECLARATIVE &&
621 18 : param->type != ISPT_NUMERICAL_DECLARATIVE) {
622 18 : if (alloc_len - total < 1) {
623 0 : SPDK_ERRLOG("data space small %d\n", alloc_len);
624 0 : return -1;
625 : }
626 :
627 18 : SPDK_DEBUGLOG(iscsi, "negotiated %s=%s\n",
628 : param->key, new_val);
629 36 : len = snprintf((char *)data + total, alloc_len - total, "%s=%s",
630 18 : param->key, new_val);
631 18 : total += len + 1;
632 18 : }
633 18 : return total;
634 18 : }
635 :
636 : /**
637 : * To negotiate param with
638 : * type = ISPT_LIST
639 : * return: the negotiated value of the key
640 : */
641 : static char *
642 7 : 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 7 : int flag = 0;
650 :
651 7 : if (add_param_value == NULL) {
652 0 : return NULL;
653 : }
654 :
655 7 : in_start = in_val;
656 7 : do {
657 9 : if ((in_end = strchr(in_start, (int)',')) != NULL) {
658 5 : *in_end = '\0';
659 5 : }
660 9 : val_start = valid_list;
661 9 : do {
662 21 : if ((val_end = strchr(val_start, (int)',')) != NULL) {
663 16 : *val_end = '\0';
664 16 : }
665 21 : if (strcasecmp(in_start, val_start) == 0) {
666 7 : SPDK_DEBUGLOG(iscsi, "match %s\n",
667 : val_start);
668 7 : flag = 1;
669 7 : break;
670 : }
671 14 : if (val_end) {
672 12 : *val_end = ',';
673 12 : val_start = val_end + 1;
674 12 : }
675 14 : } while (val_end);
676 9 : if (flag) {
677 7 : break;
678 : }
679 2 : if (in_end) {
680 2 : *in_end = ',';
681 2 : in_start = in_end + 1;
682 2 : }
683 2 : } while (in_end);
684 :
685 7 : return flag ? val_start : NULL;
686 7 : }
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 *
694 12 : 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 12 : 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 12 : if (add_param_value == NULL) {
706 0 : return NULL;
707 : }
708 :
709 12 : val_i = (int)strtol(param->val, NULL, 10);
710 : /* check whether the key is FirstBurstLength, if that we use in_val */
711 12 : if (strcasecmp(param->key, "FirstBurstLength") == 0) {
712 6 : val_i = (int)strtol(in_val, NULL, 10);
713 6 : }
714 :
715 12 : cur_val_i = (int)strtol(cur_val, NULL, 10);
716 12 : valid_next = valid_list;
717 12 : min_val = spdk_strsepq(&valid_next, ",");
718 12 : max_val = spdk_strsepq(&valid_next, ",");
719 12 : min_i = (min_val != NULL) ? (int)strtol(min_val, NULL, 10) : 0;
720 12 : max_i = (max_val != NULL) ? (int)strtol(max_val, NULL, 10) : 0;
721 12 : if (val_i < min_i || val_i > max_i) {
722 0 : SPDK_DEBUGLOG(iscsi, "key %.64s reject\n", param->key);
723 0 : new_val = NULL;
724 0 : } else {
725 12 : switch (param->type) {
726 : case ISPT_NUMERICAL_MIN:
727 12 : if (val_i > cur_val_i) {
728 0 : val_i = cur_val_i;
729 0 : }
730 12 : break;
731 : case ISPT_NUMERICAL_MAX:
732 0 : if (val_i < cur_val_i) {
733 0 : val_i = cur_val_i;
734 0 : }
735 0 : break;
736 : default:
737 0 : break;
738 : }
739 12 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d", val_i);
740 12 : new_val = in_val;
741 : }
742 :
743 12 : return new_val;
744 12 : }
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 *
752 6 : 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 6 : char *new_val = NULL;
758 :
759 6 : if (add_param_value == NULL) {
760 0 : return NULL;
761 : }
762 :
763 : /* Make sure the val is Yes or No */
764 6 : if (!((strcasecmp(in_val, "Yes") == 0) ||
765 6 : (strcasecmp(in_val, "No") == 0))) {
766 : /* unknown value */
767 6 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Reject");
768 6 : new_val = in_val;
769 6 : *add_param_value = 1;
770 6 : return new_val;
771 : }
772 :
773 0 : if (strcasecmp(cur_val, value) == 0) {
774 0 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", value);
775 0 : new_val = in_val;
776 0 : } else {
777 0 : new_val = param->val;
778 : }
779 :
780 0 : return new_val;
781 6 : }
782 :
783 : /**
784 : * The entry function to handle each type of the param
785 : * return value: the new negotiated value
786 : */
787 : static char *
788 18 : 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 18 : switch (param->type) {
793 : case ISPT_LIST:
794 0 : new_val = iscsi_negotiate_param_list(add_param_value,
795 0 : param,
796 0 : valid_list,
797 0 : in_val,
798 0 : cur_val);
799 0 : break;
800 :
801 : case ISPT_NUMERICAL_MIN:
802 : case ISPT_NUMERICAL_MAX:
803 : case ISPT_NUMERICAL_DECLARATIVE:
804 24 : new_val = iscsi_negotiate_param_numerical(add_param_value,
805 12 : param,
806 12 : valid_list,
807 12 : in_val,
808 12 : cur_val);
809 12 : break;
810 :
811 : case ISPT_BOOLEAN_OR:
812 12 : new_val = iscsi_negotiate_param_boolean(add_param_value,
813 6 : param,
814 6 : in_val,
815 6 : cur_val,
816 : "Yes");
817 6 : break;
818 : case ISPT_BOOLEAN_AND:
819 0 : new_val = iscsi_negotiate_param_boolean(add_param_value,
820 0 : param,
821 0 : in_val,
822 0 : cur_val,
823 : "No");
824 0 : break;
825 :
826 : default:
827 0 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val);
828 0 : new_val = in_val;
829 0 : break;
830 : }
831 :
832 18 : 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
840 18 : 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 18 : *cur_param_p = iscsi_param_find(*params_dst_p, param->key);
848 18 : if (*cur_param_p == NULL) {
849 18 : *params_dst_p = conn->sess->params;
850 18 : *cur_param_p = iscsi_param_find(*params_dst_p, param->key);
851 18 : if (*cur_param_p == NULL) {
852 0 : if ((strncasecmp(param->key, "X-", 2) == 0) ||
853 0 : (strncasecmp(param->key, "X#", 2) == 0)) {
854 : /* Extension Key */
855 0 : SPDK_DEBUGLOG(iscsi,
856 : "extension key %.64s\n",
857 : param->key);
858 0 : } else {
859 0 : SPDK_ERRLOG("unknown key %.64s\n", param->key);
860 : }
861 0 : return 1;
862 : } else {
863 18 : index = (*cur_param_p)->state_index;
864 18 : if (conn->sess_param_state_negotiated[index] &&
865 0 : !iscsi_find_key_in_array(param->key,
866 : target_declarative_params)) {
867 0 : return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE;
868 : }
869 18 : conn->sess_param_state_negotiated[index] = true;
870 : }
871 18 : } else {
872 0 : index = (*cur_param_p)->state_index;
873 0 : if (conn->conn_param_state_negotiated[index] &&
874 0 : !iscsi_find_key_in_array(param->key,
875 : multi_negot_conn_params)) {
876 0 : return SPDK_ISCSI_PARAMETER_EXCHANGE_NOT_ONCE;
877 : }
878 0 : conn->conn_param_state_negotiated[index] = true;
879 : }
880 :
881 18 : return 0;
882 18 : }
883 :
884 : int
885 7 : 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 7 : bool FirstBurstLength_flag = false;
900 : int type;
901 :
902 7 : total = data_len;
903 7 : if (data_len < 0) {
904 0 : assert(false);
905 : return -EINVAL;
906 : }
907 7 : if (alloc_len < 1) {
908 1 : return 0;
909 : }
910 6 : if (total > alloc_len) {
911 0 : total = alloc_len;
912 0 : data[total - 1] = '\0';
913 0 : return total;
914 : }
915 :
916 6 : if (*params == NULL) {
917 : /* no input */
918 0 : return total;
919 : }
920 :
921 : /* discovery? */
922 6 : discovery = 0;
923 6 : cur_param = iscsi_param_find(*params, "SessionType");
924 6 : if (cur_param == NULL) {
925 6 : cur_param = iscsi_param_find(conn->sess->params, "SessionType");
926 6 : if (cur_param == NULL) {
927 : /* no session type */
928 0 : } else {
929 6 : if (strcasecmp(cur_param->val, "Discovery") == 0) {
930 0 : discovery = 1;
931 0 : }
932 : }
933 6 : } else {
934 0 : if (strcasecmp(cur_param->val, "Discovery") == 0) {
935 0 : discovery = 1;
936 0 : }
937 : }
938 :
939 : /* for temporary store */
940 6 : valid_list = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
941 6 : if (!valid_list) {
942 0 : SPDK_ERRLOG("malloc() failed for valid_list\n");
943 0 : return -ENOMEM;
944 : }
945 :
946 6 : in_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
947 6 : if (!in_val) {
948 0 : SPDK_ERRLOG("malloc() failed for in_val\n");
949 0 : free(valid_list);
950 0 : return -ENOMEM;
951 : }
952 :
953 6 : cur_val = malloc(ISCSI_TEXT_MAX_VAL_LEN + 1);
954 6 : if (!cur_val) {
955 0 : SPDK_ERRLOG("malloc() failed for cur_val\n");
956 0 : free(valid_list);
957 0 : free(in_val);
958 0 : 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 6 : param = iscsi_param_find(*params, "MaxBurstLength");
965 6 : if (param != NULL) {
966 6 : param = iscsi_param_find(*params, "FirstBurstLength");
967 :
968 : /* check the existence of FirstBurstLength */
969 6 : if (param != NULL) {
970 6 : FirstBurstLength_flag = true;
971 6 : if (param->next != NULL) {
972 6 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val);
973 6 : type = param->type;
974 12 : iscsi_param_add(params, "FirstBurstLength",
975 6 : in_val, NULL, type);
976 6 : }
977 6 : }
978 6 : }
979 :
980 24 : for (param = *params; param != NULL; param = param->next) {
981 18 : struct iscsi_param *params_dst = conn->params;
982 18 : int add_param_value = 0;
983 18 : new_val = NULL;
984 18 : param->type = ISPT_INVALID;
985 :
986 : /* sendtargets is special */
987 18 : if (strcasecmp(param->key, "SendTargets") == 0) {
988 0 : continue;
989 : }
990 : /* CHAP keys */
991 18 : if (iscsi_find_key_in_array(param->key, chap_type)) {
992 0 : continue;
993 : }
994 :
995 : /* 12.2, 12.10, 12.11, 12.13, 12.14, 12.17, 12.18, 12.19 */
996 18 : if (discovery &&
997 0 : iscsi_find_key_in_array(param->key, discovery_ignored_param)) {
998 0 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "Irrelevant");
999 0 : new_val = in_val;
1000 0 : add_param_value = 1;
1001 0 : } else {
1002 36 : rc = iscsi_negotiate_param_init(conn,
1003 : &cur_param,
1004 : ¶ms_dst,
1005 18 : param);
1006 18 : if (rc < 0) {
1007 0 : free(valid_list);
1008 0 : free(in_val);
1009 0 : free(cur_val);
1010 0 : return rc;
1011 18 : } else if (rc > 0) {
1012 0 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", "NotUnderstood");
1013 0 : new_val = in_val;
1014 0 : add_param_value = 1;
1015 0 : } else {
1016 18 : snprintf(valid_list, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->list);
1017 18 : snprintf(cur_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", cur_param->val);
1018 18 : param->type = cur_param->type;
1019 : }
1020 : }
1021 :
1022 18 : if (param->type > 0) {
1023 18 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN + 1, "%s", param->val);
1024 :
1025 : /* "NotUnderstood" value shouldn't be assigned to "Understood" key */
1026 18 : if (strcasecmp(in_val, "NotUnderstood") == 0) {
1027 0 : free(in_val);
1028 0 : free(valid_list);
1029 0 : free(cur_val);
1030 0 : return SPDK_ISCSI_LOGIN_ERROR_PARAMETER;
1031 : }
1032 :
1033 18 : if (strcasecmp(param->key, "FirstBurstLength") == 0) {
1034 6 : FirstBurstLength = (uint32_t)strtol(param->val, NULL,
1035 : 10);
1036 6 : new_val = iscsi_param_get_val(conn->sess->params,
1037 : "MaxBurstLength");
1038 6 : if (new_val != NULL) {
1039 6 : MaxBurstLength = (uint32_t) strtol(new_val, NULL,
1040 : 10);
1041 6 : } else {
1042 0 : MaxBurstLength = SPDK_ISCSI_MAX_BURST_LENGTH;
1043 : }
1044 6 : if (FirstBurstLength < SPDK_ISCSI_MAX_FIRST_BURST_LENGTH &&
1045 6 : FirstBurstLength > MaxBurstLength) {
1046 2 : FirstBurstLength = MaxBurstLength;
1047 4 : snprintf(in_val, ISCSI_TEXT_MAX_VAL_LEN, "%d",
1048 2 : FirstBurstLength);
1049 2 : }
1050 6 : }
1051 :
1052 : /* prevent target's declarative params from being changed by initiator */
1053 18 : if (iscsi_find_key_in_array(param->key, target_declarative_params)) {
1054 0 : add_param_value = 1;
1055 0 : }
1056 :
1057 18 : new_val = iscsi_negotiate_param_all(&add_param_value,
1058 18 : param,
1059 18 : valid_list,
1060 18 : in_val,
1061 18 : cur_val);
1062 18 : }
1063 :
1064 : /* check the negotiated value of the key */
1065 18 : if (new_val != NULL) {
1066 : /* add_param_value = 0 means updating the value of
1067 : * existed key in the connection's parameters
1068 : */
1069 18 : if (add_param_value == 0) {
1070 12 : iscsi_param_set(params_dst, param->key, new_val);
1071 12 : }
1072 36 : total = iscsi_construct_data_from_param(param,
1073 18 : new_val,
1074 18 : data,
1075 18 : alloc_len,
1076 18 : total);
1077 18 : if (total < 0) {
1078 0 : goto final_return;
1079 : }
1080 :
1081 36 : total = iscsi_special_param_construction(conn,
1082 18 : param,
1083 18 : FirstBurstLength_flag,
1084 18 : data,
1085 18 : alloc_len,
1086 18 : total);
1087 18 : if (total < 0) {
1088 0 : goto final_return;
1089 : }
1090 18 : } else {
1091 0 : total = -1;
1092 0 : break;
1093 : }
1094 24 : }
1095 :
1096 : final_return:
1097 6 : free(valid_list);
1098 6 : free(in_val);
1099 6 : free(cur_val);
1100 :
1101 6 : return total;
1102 7 : }
1103 :
1104 : int
1105 6 : iscsi_copy_param2var(struct spdk_iscsi_conn *conn)
1106 : {
1107 : const char *val;
1108 :
1109 6 : val = iscsi_param_get_val(conn->params, "MaxRecvDataSegmentLength");
1110 6 : if (val == NULL) {
1111 0 : SPDK_ERRLOG("Getval MaxRecvDataSegmentLength failed\n");
1112 0 : return -1;
1113 : }
1114 6 : SPDK_DEBUGLOG(iscsi,
1115 : "copy MaxRecvDataSegmentLength=%s\n", val);
1116 6 : conn->MaxRecvDataSegmentLength = (int)strtol(val, NULL, 10);
1117 6 : if (conn->MaxRecvDataSegmentLength > SPDK_BDEV_LARGE_BUF_MAX_SIZE) {
1118 0 : conn->MaxRecvDataSegmentLength = SPDK_BDEV_LARGE_BUF_MAX_SIZE;
1119 0 : }
1120 :
1121 6 : val = iscsi_param_get_val(conn->params, "HeaderDigest");
1122 6 : if (val == NULL) {
1123 0 : SPDK_ERRLOG("Getval HeaderDigest failed\n");
1124 0 : return -1;
1125 : }
1126 6 : if (strcasecmp(val, "CRC32C") == 0) {
1127 0 : SPDK_DEBUGLOG(iscsi, "set HeaderDigest=1\n");
1128 0 : conn->header_digest = 1;
1129 0 : } else {
1130 6 : SPDK_DEBUGLOG(iscsi, "set HeaderDigest=0\n");
1131 6 : conn->header_digest = 0;
1132 : }
1133 6 : val = iscsi_param_get_val(conn->params, "DataDigest");
1134 6 : if (val == NULL) {
1135 0 : SPDK_ERRLOG("Getval DataDigest failed\n");
1136 0 : return -1;
1137 : }
1138 6 : if (strcasecmp(val, "CRC32C") == 0) {
1139 0 : SPDK_DEBUGLOG(iscsi, "set DataDigest=1\n");
1140 0 : conn->data_digest = 1;
1141 0 : } else {
1142 6 : SPDK_DEBUGLOG(iscsi, "set DataDigest=0\n");
1143 6 : conn->data_digest = 0;
1144 : }
1145 :
1146 6 : val = iscsi_param_get_val(conn->sess->params, "MaxConnections");
1147 6 : if (val == NULL) {
1148 0 : SPDK_ERRLOG("Getval MaxConnections failed\n");
1149 0 : return -1;
1150 : }
1151 6 : SPDK_DEBUGLOG(iscsi, "copy MaxConnections=%s\n", val);
1152 6 : conn->sess->MaxConnections = (uint32_t) strtol(val, NULL, 10);
1153 6 : val = iscsi_param_get_val(conn->sess->params, "MaxOutstandingR2T");
1154 6 : if (val == NULL) {
1155 0 : SPDK_ERRLOG("Getval MaxOutstandingR2T failed\n");
1156 0 : return -1;
1157 : }
1158 6 : SPDK_DEBUGLOG(iscsi, "copy MaxOutstandingR2T=%s\n", val);
1159 6 : conn->sess->MaxOutstandingR2T = (uint32_t) strtol(val, NULL, 10);
1160 6 : val = iscsi_param_get_val(conn->sess->params, "FirstBurstLength");
1161 6 : if (val == NULL) {
1162 0 : SPDK_ERRLOG("Getval FirstBurstLength failed\n");
1163 0 : return -1;
1164 : }
1165 6 : SPDK_DEBUGLOG(iscsi, "copy FirstBurstLength=%s\n", val);
1166 6 : conn->sess->FirstBurstLength = (uint32_t) strtol(val, NULL, 10);
1167 6 : val = iscsi_param_get_val(conn->sess->params, "MaxBurstLength");
1168 6 : if (val == NULL) {
1169 0 : SPDK_ERRLOG("Getval MaxBurstLength failed\n");
1170 0 : return -1;
1171 : }
1172 6 : SPDK_DEBUGLOG(iscsi, "copy MaxBurstLength=%s\n", val);
1173 6 : conn->sess->MaxBurstLength = (uint32_t) strtol(val, NULL, 10);
1174 6 : val = iscsi_param_get_val(conn->sess->params, "InitialR2T");
1175 6 : if (val == NULL) {
1176 0 : SPDK_ERRLOG("Getval InitialR2T failed\n");
1177 0 : return -1;
1178 : }
1179 6 : if (strcasecmp(val, "Yes") == 0) {
1180 6 : SPDK_DEBUGLOG(iscsi, "set InitialR2T=1\n");
1181 6 : conn->sess->InitialR2T = true;
1182 6 : } else {
1183 0 : SPDK_DEBUGLOG(iscsi, "set InitialR2T=0\n");
1184 0 : conn->sess->InitialR2T = false;
1185 : }
1186 6 : val = iscsi_param_get_val(conn->sess->params, "ImmediateData");
1187 6 : if (val == NULL) {
1188 0 : SPDK_ERRLOG("Getval ImmediateData failed\n");
1189 0 : return -1;
1190 : }
1191 6 : if (strcasecmp(val, "Yes") == 0) {
1192 6 : SPDK_DEBUGLOG(iscsi, "set ImmediateData=1\n");
1193 6 : conn->sess->ImmediateData = true;
1194 6 : } else {
1195 0 : SPDK_DEBUGLOG(iscsi, "set ImmediateData=0\n");
1196 0 : conn->sess->ImmediateData = false;
1197 : }
1198 6 : return 0;
1199 6 : }
|