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