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