Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/scsi.h"
9 : :
10 : : #include "spdk_internal/cunit.h"
11 : :
12 : : #include "../common.c"
13 : : #include "iscsi/param.c"
14 : :
15 : : #include "spdk_internal/mock.h"
16 : :
17 : : struct spdk_iscsi_globals g_iscsi;
18 : :
19 : 0 : DEFINE_STUB(iscsi_find_tgt_node, struct spdk_iscsi_tgt_node *,
20 : : (const char *target_name), NULL);
21 : :
22 [ # # ]: 0 : DEFINE_STUB(iscsi_tgt_node_access, bool,
23 : : (struct spdk_iscsi_conn *conn, struct spdk_iscsi_tgt_node *target,
24 : : const char *iqn, const char *addr),
25 : : false);
26 : :
27 : 0 : DEFINE_STUB(iscsi_send_tgts, int,
28 : : (struct spdk_iscsi_conn *conn, const char *iiqn, const char *iaddr,
29 : : const char *tiqn, uint8_t *data, int alloc_len, int data_len),
30 : : 0);
31 : :
32 : : static void
33 : 30 : burst_length_param_negotiation(int FirstBurstLength, int MaxBurstLength,
34 : : int initialR2T)
35 : : {
36 : 24 : struct spdk_iscsi_sess sess;
37 : 24 : struct spdk_iscsi_conn conn;
38 : 24 : struct iscsi_param *params;
39 : 6 : struct iscsi_param **params_p;
40 : 24 : char data[8192];
41 : 6 : int rc;
42 : 6 : int total, len;
43 : :
44 : 30 : total = 0;
45 : 30 : params = NULL;
46 : 30 : params_p = ¶ms;
47 : :
48 [ + + ]: 30 : memset(&sess, 0, sizeof(sess));
49 [ + + ]: 30 : memset(&conn, 0, sizeof(conn));
50 [ + + ]: 30 : memset(data, 0, 8192);
51 : :
52 [ + - ]: 30 : sess.ExpCmdSN = 0;
53 [ + - ]: 30 : sess.MaxCmdSN = 64;
54 [ + - ]: 30 : sess.session_type = SESSION_TYPE_NORMAL;
55 [ + - ]: 30 : sess.params = NULL;
56 [ + - ]: 30 : sess.MaxBurstLength = 65536;
57 [ + - ]: 30 : sess.InitialR2T = true;
58 [ + - ]: 30 : sess.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
59 [ + - ]: 30 : sess.MaxOutstandingR2T = 1;
60 : :
61 : : /* set default params */
62 : 30 : rc = iscsi_sess_params_init(&sess.params);
63 : 30 : CU_ASSERT(rc == 0);
64 : :
65 [ + - ]: 30 : rc = iscsi_param_set_int(sess.params, "FirstBurstLength",
66 [ + - ]: 6 : sess.FirstBurstLength);
67 : 30 : CU_ASSERT(rc == 0);
68 : :
69 [ + - ]: 30 : rc = iscsi_param_set_int(sess.params, "MaxBurstLength",
70 [ + - ]: 6 : sess.MaxBurstLength);
71 : 30 : CU_ASSERT(rc == 0);
72 : :
73 [ + - ]: 36 : rc = iscsi_param_set(sess.params, "InitialR2T",
74 [ + + + - ]: 30 : sess.InitialR2T ? "Yes" : "No");
75 : 30 : CU_ASSERT(rc == 0);
76 : :
77 [ + - ]: 30 : conn.full_feature = 1;
78 [ + - ]: 30 : conn.sess = &sess;
79 [ + - ]: 30 : conn.MaxRecvDataSegmentLength = 65536;
80 : :
81 : 30 : rc = iscsi_conn_params_init(&conn.params);
82 : 30 : CU_ASSERT(rc == 0);
83 : :
84 : : /* construct the data */
85 [ + + + - : 30 : len = snprintf(data + total, 8192 - total, "%s=%d",
+ - ]
86 : 6 : "FirstBurstLength", FirstBurstLength);
87 [ + - + - ]: 30 : total += len + 1;
88 : :
89 [ + + + - : 30 : len = snprintf(data + total, 8192 - total, "%s=%d",
+ - ]
90 : 6 : "MaxBurstLength", MaxBurstLength);
91 [ + - + - ]: 30 : total += len + 1;
92 : :
93 [ + + + - : 30 : len = snprintf(data + total, 8192 - total, "%s=%d",
+ - ]
94 : 6 : "InitialR2T", initialR2T);
95 [ + - + - ]: 30 : total += len + 1;
96 : :
97 : : /* add one extra NUL byte at the end to match real iSCSI params */
98 [ + - ]: 30 : total++;
99 : :
100 : : /* store incoming parameters */
101 : 30 : rc = iscsi_parse_params(params_p, data, total, false, NULL);
102 : 30 : CU_ASSERT(rc == 0);
103 : :
104 : : /* negotiate parameters */
105 : 36 : rc = iscsi_negotiate_params(&conn, params_p,
106 : 6 : data, 8192, rc);
107 : 30 : CU_ASSERT(rc > 0);
108 : :
109 : 30 : rc = iscsi_copy_param2var(&conn);
110 : 30 : CU_ASSERT(rc == 0);
111 [ + - + - : 30 : CU_ASSERT(conn.sess->FirstBurstLength <= SPDK_ISCSI_FIRST_BURST_LENGTH);
+ - ]
112 [ + - + - : 30 : CU_ASSERT(conn.sess->FirstBurstLength <= conn.sess->MaxBurstLength);
+ - + - +
- + - ]
113 [ + - + - : 30 : CU_ASSERT(conn.sess->MaxBurstLength <= SPDK_ISCSI_MAX_BURST_LENGTH);
+ - ]
114 [ + - + - : 30 : CU_ASSERT(conn.sess->MaxOutstandingR2T == 1);
+ - ]
115 : :
116 [ + - ]: 30 : iscsi_param_free(sess.params);
117 [ + - ]: 30 : iscsi_param_free(conn.params);
118 [ + - ]: 30 : iscsi_param_free(*params_p);
119 : 30 : }
120 : :
121 : : static void
122 : 5 : param_negotiation_test(void)
123 : : {
124 : 5 : burst_length_param_negotiation(8192, 16384, 0);
125 : 5 : burst_length_param_negotiation(8192, 16384, 1);
126 : 5 : burst_length_param_negotiation(8192, 1024, 1);
127 : 5 : burst_length_param_negotiation(8192, 1024, 0);
128 : 5 : burst_length_param_negotiation(512, 1024, 1);
129 : 5 : burst_length_param_negotiation(512, 1024, 0);
130 : 5 : }
131 : :
132 : : static void
133 : 5 : list_negotiation_test(void)
134 : : {
135 : 5 : int add_param_value = 0;
136 : 5 : struct iscsi_param param = {};
137 : 1 : char *new_val;
138 : 4 : char valid_list_buf[1024];
139 : 4 : char in_val_buf[1024];
140 : :
141 : : #define TEST_LIST(valid_list, in_val, expected_result) \
142 : : do { \
143 : : snprintf(valid_list_buf, sizeof(valid_list_buf), "%s", valid_list); \
144 : : snprintf(in_val_buf, sizeof(in_val_buf), "%s", in_val); \
145 : : new_val = iscsi_negotiate_param_list(&add_param_value, ¶m, valid_list_buf, in_val_buf, NULL); \
146 : : if (expected_result) { \
147 : : SPDK_CU_ASSERT_FATAL(new_val != NULL); \
148 : : CU_ASSERT_STRING_EQUAL(new_val, expected_result); \
149 : : } \
150 : : } while (0)
151 : :
152 [ - + + + : 5 : TEST_LIST("None", "None", "None");
# # + - +
- ]
153 [ - + + + : 5 : TEST_LIST("CHAP,None", "None", "None");
# # + - +
- ]
154 [ - + + + : 5 : TEST_LIST("CHAP,None", "CHAP", "CHAP");
# # + - +
- ]
155 [ - + + + : 5 : TEST_LIST("KRB5,SRP,CHAP,None", "SRP,CHAP,None", "SRP");
# # + - +
- ]
156 [ - + + + : 5 : TEST_LIST("KRB5,SRP,CHAP,None", "CHAP,SRP,None", "CHAP");
# # + - +
- ]
157 [ - + + + : 5 : TEST_LIST("KRB5,SRP,CHAP,None", "SPKM1,SRP,CHAP,None", "SRP");
# # + - +
- ]
158 [ - + + + : 5 : TEST_LIST("KRB5,SRP,None", "CHAP,None", "None");
# # + - +
- ]
159 : 5 : }
160 : :
161 : : #define PARSE(strconst, partial_enabled, partial_text) \
162 : : data = strconst; \
163 : : len = sizeof(strconst) - 1; \
164 : : rc = iscsi_parse_params(¶ms, data, len, partial_enabled, partial_text)
165 : :
166 : : #define EXPECT_VAL(key, expected_value) \
167 : : { \
168 : : const char *val = iscsi_param_get_val(params, key); \
169 : : CU_ASSERT(val != NULL); \
170 : : if (val != NULL) { \
171 : : CU_ASSERT(strcmp(val, expected_value) == 0); \
172 : : } \
173 : : }
174 : :
175 : : #define EXPECT_NULL(key) \
176 : : CU_ASSERT(iscsi_param_get_val(params, key) == NULL)
177 : :
178 : : static void
179 : 5 : parse_valid_test(void)
180 : : {
181 : 5 : struct iscsi_param *params = NULL;
182 : 1 : int rc;
183 : 1 : char *data;
184 : 1 : int len;
185 : 5 : char *partial_parameter = NULL;
186 : :
187 : : /* simple test with a single key=value */
188 : 5 : PARSE("Abc=def\0", false, NULL);
189 : 5 : CU_ASSERT(rc == 0);
190 [ + + + + : 5 : EXPECT_VAL("Abc", "def");
+ - ]
191 : :
192 : : /* multiple key=value pairs */
193 : 5 : PARSE("Aaa=bbbbbb\0Xyz=test\0", false, NULL);
194 : 5 : CU_ASSERT(rc == 0);
195 [ + + + + : 5 : EXPECT_VAL("Aaa", "bbbbbb");
+ - ]
196 [ + + + + : 5 : EXPECT_VAL("Xyz", "test");
+ - ]
197 : :
198 : : /* value with embedded '=' */
199 : 5 : PARSE("A=b=c\0", false, NULL);
200 : 5 : CU_ASSERT(rc == 0);
201 [ + + + + : 5 : EXPECT_VAL("A", "b=c");
+ - ]
202 : :
203 : : /* CHAP_C=AAAA.... with value length 8192 */
204 : 5 : len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1/* null terminators */;
205 : 5 : data = malloc(len);
206 [ + + # # ]: 5 : SPDK_CU_ASSERT_FATAL(data != NULL);
207 [ + + ]: 5 : memset(data, 'A', len);
208 [ + + + - ]: 5 : memcpy(data, "CHAP_C", 6);
209 [ + - + - ]: 5 : data[6] = '=';
210 [ + - + - : 5 : data[len - 1] = '\0';
+ - ]
211 : 5 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
212 : 5 : CU_ASSERT(rc == 0);
213 : 5 : free(data);
214 : :
215 : : /* partial parameter: value is partial */
216 : 5 : PARSE("C=AAA\0D=B", true, &partial_parameter);
217 [ + + # # ]: 5 : SPDK_CU_ASSERT_FATAL(partial_parameter != NULL);
218 [ + + + - ]: 5 : CU_ASSERT_STRING_EQUAL(partial_parameter, "D=B");
219 : 5 : CU_ASSERT(rc == 0);
220 [ + + + + : 5 : EXPECT_VAL("C", "AAA");
+ - ]
221 : 5 : EXPECT_NULL("D");
222 : 5 : PARSE("XXXX\0E=UUUU\0", false, &partial_parameter);
223 : 5 : CU_ASSERT(rc == 0);
224 [ + + + + : 5 : EXPECT_VAL("D", "BXXXX");
+ - ]
225 [ + + + + : 5 : EXPECT_VAL("E", "UUUU");
+ - ]
226 : 5 : CU_ASSERT_PTR_NULL(partial_parameter);
227 : :
228 : : /* partial parameter: key is partial */
229 : 5 : PARSE("IAMAFAK", true, &partial_parameter);
230 [ + + + - ]: 5 : CU_ASSERT_STRING_EQUAL(partial_parameter, "IAMAFAK");
231 : 5 : CU_ASSERT(rc == 0);
232 : 5 : EXPECT_NULL("IAMAFAK");
233 : 5 : PARSE("EDKEY=TTTT\0F=IIII", false, &partial_parameter);
234 : 5 : CU_ASSERT(rc == 0);
235 [ + + + + : 5 : EXPECT_VAL("IAMAFAKEDKEY", "TTTT");
+ - ]
236 [ + + + + : 5 : EXPECT_VAL("F", "IIII");
+ - ]
237 : 5 : CU_ASSERT_PTR_NULL(partial_parameter);
238 : :
239 : : /* partial parameter: NULL data */
240 : : /* It is technically allowed to have a TEXT PDU with no data, yet
241 : : * CONTINUE bit is enabled - make sure we handle that case correctly.
242 : : */
243 : 5 : rc = iscsi_parse_params(¶ms, NULL, 0, true, &partial_parameter);
244 : 5 : CU_ASSERT(rc == 0);
245 : 5 : CU_ASSERT_PTR_NULL(partial_parameter);
246 : :
247 : : /* Second partial parameter is the only parameter */
248 : 5 : PARSE("OOOO", true, &partial_parameter);
249 [ + + + - ]: 5 : CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
250 : 5 : CU_ASSERT(rc == 0);
251 : 5 : EXPECT_NULL("OOOO");
252 : 5 : PARSE("LL=MMMM", false, &partial_parameter);
253 : 5 : CU_ASSERT(rc == 0);
254 [ + + + + : 5 : EXPECT_VAL("OOOOLL", "MMMM");
+ - ]
255 : 5 : CU_ASSERT_PTR_NULL(partial_parameter);
256 : :
257 : 5 : partial_parameter = NULL;
258 : 5 : data = "PartialKey=";
259 : 5 : len = 7;
260 : 5 : rc = iscsi_parse_params(¶ms, data, len, true, &partial_parameter);
261 : 5 : CU_ASSERT(rc == 0);
262 [ + + + - ]: 5 : CU_ASSERT_STRING_EQUAL(partial_parameter, "Partial");
263 : 5 : EXPECT_NULL("PartialKey");
264 : 5 : PARSE("Key=Value", false, &partial_parameter);
265 : 5 : CU_ASSERT(rc == 0);
266 [ + + + + : 5 : EXPECT_VAL("PartialKey", "Value");
+ - ]
267 : 5 : CU_ASSERT_PTR_NULL(partial_parameter);
268 : :
269 : 5 : iscsi_param_free(params);
270 : 5 : }
271 : :
272 : : static void
273 : 5 : parse_invalid_test(void)
274 : : {
275 : 5 : struct iscsi_param *params = NULL;
276 : 1 : int rc;
277 : 1 : char *data;
278 : 1 : int len;
279 : :
280 : : /* key without '=' */
281 : 5 : PARSE("Abc\0", false, NULL);
282 : 5 : CU_ASSERT(rc != 0);
283 : 5 : EXPECT_NULL("Abc");
284 : :
285 : : /* multiple key=value pairs, one missing '=' */
286 : 5 : PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL);
287 : 5 : CU_ASSERT(rc != 0);
288 [ + + + + : 5 : EXPECT_VAL("Abc", "def");
+ - ]
289 : 5 : EXPECT_NULL("Xyz");
290 : 5 : EXPECT_NULL("Www");
291 : :
292 : : /* empty key */
293 : 5 : PARSE("=abcdef", false, NULL);
294 : 5 : CU_ASSERT(rc != 0);
295 : 5 : EXPECT_NULL("");
296 : :
297 : : /* CHAP_C=AAAA.... with value length 8192 + 1 */
298 : 5 : len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ +
299 : : 1 /* null terminators */;
300 : 5 : data = malloc(len);
301 [ + + # # ]: 5 : SPDK_CU_ASSERT_FATAL(data != NULL);
302 [ + + ]: 5 : memset(data, 'A', len);
303 [ + + + - ]: 5 : memcpy(data, "CHAP_C", 6);
304 [ + - + - ]: 5 : data[6] = '=';
305 [ + - + - : 5 : data[len - 1] = '\0';
+ - ]
306 : 5 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
307 : 5 : free(data);
308 : 5 : CU_ASSERT(rc != 0);
309 : 5 : EXPECT_NULL("CHAP_C");
310 : :
311 : : /* Test simple value, length of value bigger than 255 */
312 : 5 : len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ +
313 : : 1 /* null terminators */;
314 : 5 : data = malloc(len);
315 [ + + # # ]: 5 : SPDK_CU_ASSERT_FATAL(data != NULL);
316 [ + + ]: 5 : memset(data, 'A', len);
317 [ + - + - ]: 5 : data[1] = '=';
318 [ + - + - : 5 : data[len - 1] = '\0';
+ - ]
319 : 5 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
320 : 5 : free(data);
321 : 5 : CU_ASSERT(rc != 0);
322 : 5 : EXPECT_NULL("A");
323 : :
324 : : /* key length bigger than 63 */
325 : 5 : len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ +
326 : : 1 /* null terminators */;
327 : 5 : data = malloc(len);
328 [ + + # # ]: 5 : SPDK_CU_ASSERT_FATAL(data != NULL);
329 [ + + ]: 5 : memset(data, 'A', len);
330 [ + - + - ]: 5 : data[64] = '=';
331 [ + - + - : 5 : data[len - 1] = '\0';
+ - ]
332 : 5 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
333 : 5 : free(data);
334 : 5 : CU_ASSERT(rc != 0);
335 : 5 : EXPECT_NULL("A");
336 : :
337 : : /* duplicated key */
338 : 5 : PARSE("B=BB", false, NULL);
339 : 5 : CU_ASSERT(rc == 0);
340 : 5 : PARSE("B=BBBB", false, NULL);
341 : 5 : CU_ASSERT(rc != 0);
342 [ + + + + : 5 : EXPECT_VAL("B", "BB");
+ - ]
343 : :
344 : : /* Test where data buffer has non-NULL characters past the end of
345 : : * the valid data region. This can happen with SPDK iSCSI target,
346 : : * since data buffers are reused and we do not zero the data buffers
347 : : * after they are freed since it would be too expensive. Added as
348 : : * part of fixing an intermittent Calsoft failure that triggered this
349 : : * bug.
350 : : */
351 : 5 : data = "MaxRecvDataSegmentLength=81928";
352 [ + + ]: 5 : len = strlen(data) - 1;
353 : 5 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
354 [ + + + + : 5 : EXPECT_VAL("MaxRecvDataSegmentLength", "8192");
+ - ]
355 : 5 : CU_ASSERT(rc == 0);
356 : 5 : iscsi_param_free(params);
357 : 5 : }
358 : :
359 : : int
360 : 5 : main(int argc, char **argv)
361 : : {
362 : 5 : CU_pSuite suite = NULL;
363 : 1 : unsigned int num_failures;
364 : :
365 : 5 : CU_initialize_registry();
366 : :
367 : 5 : suite = CU_add_suite("iscsi_suite", NULL, NULL);
368 : :
369 : 5 : CU_ADD_TEST(suite, param_negotiation_test);
370 : 5 : CU_ADD_TEST(suite, list_negotiation_test);
371 : 5 : CU_ADD_TEST(suite, parse_valid_test);
372 : 5 : CU_ADD_TEST(suite, parse_invalid_test);
373 : :
374 : 5 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
375 : 5 : CU_cleanup_registry();
376 : 6 : return num_failures;
377 : 1 : }
|