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 : 36 : burst_length_param_negotiation(int FirstBurstLength, int MaxBurstLength,
34 : : int initialR2T)
35 : : {
36 : 30 : struct spdk_iscsi_sess sess;
37 : 30 : struct spdk_iscsi_conn conn;
38 : 30 : struct iscsi_param *params;
39 : : struct iscsi_param **params_p;
40 : 30 : char data[8192];
41 : : int rc;
42 : : int total, len;
43 : :
44 : 36 : total = 0;
45 : 36 : params = NULL;
46 : 36 : params_p = ¶ms;
47 : :
48 [ - + ]: 36 : memset(&sess, 0, sizeof(sess));
49 [ - + ]: 36 : memset(&conn, 0, sizeof(conn));
50 [ - + ]: 36 : memset(data, 0, 8192);
51 : :
52 : 36 : sess.ExpCmdSN = 0;
53 : 36 : sess.MaxCmdSN = 64;
54 : 36 : sess.session_type = SESSION_TYPE_NORMAL;
55 : 36 : sess.params = NULL;
56 : 36 : sess.MaxBurstLength = 65536;
57 : 36 : sess.InitialR2T = true;
58 : 36 : sess.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
59 : 36 : sess.MaxOutstandingR2T = 1;
60 : :
61 : : /* set default params */
62 : 36 : rc = iscsi_sess_params_init(&sess.params);
63 : 36 : CU_ASSERT(rc == 0);
64 : :
65 : 36 : rc = iscsi_param_set_int(sess.params, "FirstBurstLength",
66 : : sess.FirstBurstLength);
67 : 36 : CU_ASSERT(rc == 0);
68 : :
69 : 36 : rc = iscsi_param_set_int(sess.params, "MaxBurstLength",
70 : : sess.MaxBurstLength);
71 : 36 : CU_ASSERT(rc == 0);
72 : :
73 : 36 : rc = iscsi_param_set(sess.params, "InitialR2T",
74 [ + + + - ]: 36 : sess.InitialR2T ? "Yes" : "No");
75 : 36 : CU_ASSERT(rc == 0);
76 : :
77 : 36 : conn.full_feature = 1;
78 : 36 : conn.sess = &sess;
79 : 36 : conn.MaxRecvDataSegmentLength = 65536;
80 : :
81 : 36 : rc = iscsi_conn_params_init(&conn.params);
82 : 36 : CU_ASSERT(rc == 0);
83 : :
84 : : /* construct the data */
85 [ - + ]: 36 : len = snprintf(data + total, 8192 - total, "%s=%d",
86 : : "FirstBurstLength", FirstBurstLength);
87 : 36 : total += len + 1;
88 : :
89 [ - + ]: 36 : len = snprintf(data + total, 8192 - total, "%s=%d",
90 : : "MaxBurstLength", MaxBurstLength);
91 : 36 : total += len + 1;
92 : :
93 [ - + ]: 36 : len = snprintf(data + total, 8192 - total, "%s=%d",
94 : : "InitialR2T", initialR2T);
95 : 36 : total += len + 1;
96 : :
97 : : /* add one extra NUL byte at the end to match real iSCSI params */
98 : 36 : total++;
99 : :
100 : : /* store incoming parameters */
101 : 36 : rc = iscsi_parse_params(params_p, data, total, false, NULL);
102 : 36 : CU_ASSERT(rc == 0);
103 : :
104 : : /* negotiate parameters */
105 : 36 : rc = iscsi_negotiate_params(&conn, params_p,
106 : : data, 8192, rc);
107 : 36 : CU_ASSERT(rc > 0);
108 : :
109 : 36 : rc = iscsi_copy_param2var(&conn);
110 : 36 : CU_ASSERT(rc == 0);
111 : 36 : CU_ASSERT(conn.sess->FirstBurstLength <= SPDK_ISCSI_FIRST_BURST_LENGTH);
112 : 36 : CU_ASSERT(conn.sess->FirstBurstLength <= conn.sess->MaxBurstLength);
113 : 36 : CU_ASSERT(conn.sess->MaxBurstLength <= SPDK_ISCSI_MAX_BURST_LENGTH);
114 : 36 : CU_ASSERT(conn.sess->MaxOutstandingR2T == 1);
115 : :
116 : 36 : iscsi_param_free(sess.params);
117 : 36 : iscsi_param_free(conn.params);
118 : 36 : iscsi_param_free(*params_p);
119 : 36 : }
120 : :
121 : : static void
122 : 6 : param_negotiation_test(void)
123 : : {
124 : 6 : burst_length_param_negotiation(8192, 16384, 0);
125 : 6 : burst_length_param_negotiation(8192, 16384, 1);
126 : 6 : burst_length_param_negotiation(8192, 1024, 1);
127 : 6 : burst_length_param_negotiation(8192, 1024, 0);
128 : 6 : burst_length_param_negotiation(512, 1024, 1);
129 : 6 : burst_length_param_negotiation(512, 1024, 0);
130 : 6 : }
131 : :
132 : : static void
133 : 6 : list_negotiation_test(void)
134 : : {
135 : 6 : int add_param_value = 0;
136 : 6 : struct iscsi_param param = {};
137 : : char *new_val;
138 : 5 : char valid_list_buf[1024];
139 : 5 : 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 [ - + - + ]: 6 : TEST_LIST("None", "None", "None");
153 [ - + - + ]: 6 : TEST_LIST("CHAP,None", "None", "None");
154 [ - + - + ]: 6 : TEST_LIST("CHAP,None", "CHAP", "CHAP");
155 [ - + - + ]: 6 : TEST_LIST("KRB5,SRP,CHAP,None", "SRP,CHAP,None", "SRP");
156 [ - + - + ]: 6 : TEST_LIST("KRB5,SRP,CHAP,None", "CHAP,SRP,None", "CHAP");
157 [ - + - + ]: 6 : TEST_LIST("KRB5,SRP,CHAP,None", "SPKM1,SRP,CHAP,None", "SRP");
158 [ - + - + ]: 6 : TEST_LIST("KRB5,SRP,None", "CHAP,None", "None");
159 : 6 : }
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 : 6 : parse_valid_test(void)
180 : : {
181 : 6 : struct iscsi_param *params = NULL;
182 : : int rc;
183 : : char *data;
184 : : int len;
185 : 6 : char *partial_parameter = NULL;
186 : :
187 : : /* simple test with a single key=value */
188 : 6 : PARSE("Abc=def\0", false, NULL);
189 : 6 : CU_ASSERT(rc == 0);
190 [ + - - + ]: 6 : EXPECT_VAL("Abc", "def");
191 : :
192 : : /* multiple key=value pairs */
193 : 6 : PARSE("Aaa=bbbbbb\0Xyz=test\0", false, NULL);
194 : 6 : CU_ASSERT(rc == 0);
195 [ + - - + ]: 6 : EXPECT_VAL("Aaa", "bbbbbb");
196 [ + - - + ]: 6 : EXPECT_VAL("Xyz", "test");
197 : :
198 : : /* value with embedded '=' */
199 : 6 : PARSE("A=b=c\0", false, NULL);
200 : 6 : CU_ASSERT(rc == 0);
201 [ + - - + ]: 6 : EXPECT_VAL("A", "b=c");
202 : :
203 : : /* CHAP_C=AAAA.... with value length 8192 */
204 : 6 : len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1/* null terminators */;
205 : 6 : data = malloc(len);
206 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(data != NULL);
207 [ - + ]: 6 : memset(data, 'A', len);
208 [ - + ]: 6 : memcpy(data, "CHAP_C", 6);
209 : 6 : data[6] = '=';
210 : 6 : data[len - 1] = '\0';
211 : 6 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
212 : 6 : CU_ASSERT(rc == 0);
213 : 6 : free(data);
214 : :
215 : : /* partial parameter: value is partial */
216 : 6 : PARSE("C=AAA\0D=B", true, &partial_parameter);
217 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(partial_parameter != NULL);
218 [ - + ]: 6 : CU_ASSERT_STRING_EQUAL(partial_parameter, "D=B");
219 : 6 : CU_ASSERT(rc == 0);
220 [ + - - + ]: 6 : EXPECT_VAL("C", "AAA");
221 : 6 : EXPECT_NULL("D");
222 : 6 : PARSE("XXXX\0E=UUUU\0", false, &partial_parameter);
223 : 6 : CU_ASSERT(rc == 0);
224 [ + - - + ]: 6 : EXPECT_VAL("D", "BXXXX");
225 [ + - - + ]: 6 : EXPECT_VAL("E", "UUUU");
226 : 6 : CU_ASSERT_PTR_NULL(partial_parameter);
227 : :
228 : : /* partial parameter: key is partial */
229 : 6 : PARSE("IAMAFAK", true, &partial_parameter);
230 [ - + ]: 6 : CU_ASSERT_STRING_EQUAL(partial_parameter, "IAMAFAK");
231 : 6 : CU_ASSERT(rc == 0);
232 : 6 : EXPECT_NULL("IAMAFAK");
233 : 6 : PARSE("EDKEY=TTTT\0F=IIII", false, &partial_parameter);
234 : 6 : CU_ASSERT(rc == 0);
235 [ + - - + ]: 6 : EXPECT_VAL("IAMAFAKEDKEY", "TTTT");
236 [ + - - + ]: 6 : EXPECT_VAL("F", "IIII");
237 : 6 : 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 : 6 : rc = iscsi_parse_params(¶ms, NULL, 0, true, &partial_parameter);
244 : 6 : CU_ASSERT(rc == 0);
245 : 6 : CU_ASSERT_PTR_NULL(partial_parameter);
246 : :
247 : : /* Second partial parameter is the only parameter */
248 : 6 : PARSE("OOOO", true, &partial_parameter);
249 [ - + ]: 6 : CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
250 : 6 : CU_ASSERT(rc == 0);
251 : 6 : EXPECT_NULL("OOOO");
252 : 6 : PARSE("LL=MMMM", false, &partial_parameter);
253 : 6 : CU_ASSERT(rc == 0);
254 [ + - - + ]: 6 : EXPECT_VAL("OOOOLL", "MMMM");
255 : 6 : CU_ASSERT_PTR_NULL(partial_parameter);
256 : :
257 : 6 : partial_parameter = NULL;
258 : 6 : data = "PartialKey=";
259 : 6 : len = 7;
260 : 6 : rc = iscsi_parse_params(¶ms, data, len, true, &partial_parameter);
261 : 6 : CU_ASSERT(rc == 0);
262 [ - + ]: 6 : CU_ASSERT_STRING_EQUAL(partial_parameter, "Partial");
263 : 6 : EXPECT_NULL("PartialKey");
264 : 6 : PARSE("Key=Value", false, &partial_parameter);
265 : 6 : CU_ASSERT(rc == 0);
266 [ + - - + ]: 6 : EXPECT_VAL("PartialKey", "Value");
267 : 6 : CU_ASSERT_PTR_NULL(partial_parameter);
268 : :
269 : 6 : iscsi_param_free(params);
270 : 6 : }
271 : :
272 : : static void
273 : 6 : parse_invalid_test(void)
274 : : {
275 : 6 : struct iscsi_param *params = NULL;
276 : : int rc;
277 : : char *data;
278 : : int len;
279 : :
280 : : /* key without '=' */
281 : 6 : PARSE("Abc\0", false, NULL);
282 : 6 : CU_ASSERT(rc != 0);
283 : 6 : EXPECT_NULL("Abc");
284 : :
285 : : /* multiple key=value pairs, one missing '=' */
286 : 6 : PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL);
287 : 6 : CU_ASSERT(rc != 0);
288 [ + - - + ]: 6 : EXPECT_VAL("Abc", "def");
289 : 6 : EXPECT_NULL("Xyz");
290 : 6 : EXPECT_NULL("Www");
291 : :
292 : : /* empty key */
293 : 6 : PARSE("=abcdef", false, NULL);
294 : 6 : CU_ASSERT(rc != 0);
295 : 6 : EXPECT_NULL("");
296 : :
297 : : /* CHAP_C=AAAA.... with value length 8192 + 1 */
298 : 6 : len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ +
299 : : 1 /* null terminators */;
300 : 6 : data = malloc(len);
301 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(data != NULL);
302 [ - + ]: 6 : memset(data, 'A', len);
303 [ - + ]: 6 : memcpy(data, "CHAP_C", 6);
304 : 6 : data[6] = '=';
305 : 6 : data[len - 1] = '\0';
306 : 6 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
307 : 6 : free(data);
308 : 6 : CU_ASSERT(rc != 0);
309 : 6 : EXPECT_NULL("CHAP_C");
310 : :
311 : : /* Test simple value, length of value bigger than 255 */
312 : 6 : len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ +
313 : : 1 /* null terminators */;
314 : 6 : data = malloc(len);
315 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(data != NULL);
316 [ - + ]: 6 : memset(data, 'A', len);
317 : 6 : data[1] = '=';
318 : 6 : data[len - 1] = '\0';
319 : 6 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
320 : 6 : free(data);
321 : 6 : CU_ASSERT(rc != 0);
322 : 6 : EXPECT_NULL("A");
323 : :
324 : : /* key length bigger than 63 */
325 : 6 : len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ +
326 : : 1 /* null terminators */;
327 : 6 : data = malloc(len);
328 [ - + ]: 6 : SPDK_CU_ASSERT_FATAL(data != NULL);
329 [ - + ]: 6 : memset(data, 'A', len);
330 : 6 : data[64] = '=';
331 : 6 : data[len - 1] = '\0';
332 : 6 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
333 : 6 : free(data);
334 : 6 : CU_ASSERT(rc != 0);
335 : 6 : EXPECT_NULL("A");
336 : :
337 : : /* duplicated key */
338 : 6 : PARSE("B=BB", false, NULL);
339 : 6 : CU_ASSERT(rc == 0);
340 : 6 : PARSE("B=BBBB", false, NULL);
341 : 6 : CU_ASSERT(rc != 0);
342 [ + - - + ]: 6 : 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 : 6 : data = "MaxRecvDataSegmentLength=81928";
352 [ - + ]: 6 : len = strlen(data) - 1;
353 : 6 : rc = iscsi_parse_params(¶ms, data, len, false, NULL);
354 [ + - - + ]: 6 : EXPECT_VAL("MaxRecvDataSegmentLength", "8192");
355 : 6 : CU_ASSERT(rc == 0);
356 : 6 : iscsi_param_free(params);
357 : 6 : }
358 : :
359 : : int
360 : 6 : main(int argc, char **argv)
361 : : {
362 : 6 : CU_pSuite suite = NULL;
363 : : unsigned int num_failures;
364 : :
365 : 6 : CU_initialize_registry();
366 : :
367 : 6 : suite = CU_add_suite("iscsi_suite", NULL, NULL);
368 : :
369 : 6 : CU_ADD_TEST(suite, param_negotiation_test);
370 : 6 : CU_ADD_TEST(suite, list_negotiation_test);
371 : 6 : CU_ADD_TEST(suite, parse_valid_test);
372 : 6 : CU_ADD_TEST(suite, parse_invalid_test);
373 : :
374 : 6 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
375 : 6 : CU_cleanup_registry();
376 : 6 : return num_failures;
377 : : }
|