xref: /spdk/test/unit/lib/iscsi/param.c/param_ut.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
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
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 = &params;
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
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
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, &param, 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(&params, 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 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(&params, 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(&params, 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(&params, 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
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(&params, 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(&params, 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(&params, 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(&params, data, len, false, NULL);
354 	EXPECT_VAL("MaxRecvDataSegmentLength", "8192");
355 	CU_ASSERT(rc == 0);
356 	iscsi_param_free(params);
357 }
358 
359 int
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