xref: /spdk/test/unit/lib/iscsi/param.c/param_ut.c (revision 22898a91b9b6f289933db19b0175821cfb7e7820)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "spdk/scsi.h"
37 
38 #include "spdk_cunit.h"
39 
40 #include "../common.c"
41 #include "iscsi/param.c"
42 
43 struct spdk_iscsi_globals g_spdk_iscsi;
44 
45 struct spdk_iscsi_tgt_node *
46 spdk_iscsi_find_tgt_node(const char *target_name)
47 {
48 	return NULL;
49 }
50 
51 bool
52 spdk_iscsi_tgt_node_access(struct spdk_iscsi_conn *conn,
53 			   struct spdk_iscsi_tgt_node *target,
54 			   const char *iqn, const char *addr)
55 {
56 	return false;
57 }
58 
59 int
60 spdk_iscsi_send_tgts(struct spdk_iscsi_conn *conn, const char *iiqn,
61 		     const char *iaddr,
62 		     const char *tiqn, uint8_t *data, int alloc_len, int data_len)
63 {
64 	return 0;
65 }
66 
67 static void
68 burst_length_param_negotation(int FirstBurstLength, int MaxBurstLength,
69 			      int initialR2T)
70 {
71 	struct spdk_iscsi_sess sess;
72 	struct spdk_iscsi_conn conn;
73 	struct iscsi_param *params;
74 	struct iscsi_param **params_p;
75 	char data[8192];
76 	int rc;
77 	int total, len;
78 
79 	total = 0;
80 	params = NULL;
81 	params_p = &params;
82 
83 	memset(&sess, 0, sizeof(sess));
84 	memset(&conn, 0, sizeof(conn));
85 	memset(data, 0, 8192);
86 
87 	sess.ExpCmdSN = 0;
88 	sess.MaxCmdSN = 64;
89 	sess.session_type = SESSION_TYPE_NORMAL;
90 	sess.params = NULL;
91 	sess.MaxBurstLength = 65536;
92 	sess.InitialR2T = true;
93 	sess.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
94 	sess.MaxOutstandingR2T = 1;
95 
96 	/* set default params */
97 	rc = spdk_iscsi_sess_params_init(&sess.params);
98 	CU_ASSERT(rc == 0);
99 
100 	rc = spdk_iscsi_param_set_int(sess.params, "FirstBurstLength",
101 				      sess.FirstBurstLength);
102 	CU_ASSERT(rc == 0);
103 
104 	rc = spdk_iscsi_param_set_int(sess.params, "MaxBurstLength",
105 				      sess.MaxBurstLength);
106 	CU_ASSERT(rc == 0);
107 
108 	rc = spdk_iscsi_param_set(sess.params, "InitialR2T",
109 				  sess.InitialR2T ? "Yes" : "No");
110 	CU_ASSERT(rc == 0);
111 
112 	conn.full_feature = 1;
113 	conn.sess = &sess;
114 	conn.MaxRecvDataSegmentLength = 65536;
115 
116 	rc = spdk_iscsi_conn_params_init(&conn.params);
117 	CU_ASSERT(rc == 0);
118 
119 	/* construct the data */
120 	len = snprintf(data + total, 8192 - total, "%s=%d",
121 		       "FirstBurstLength", FirstBurstLength);
122 	total += len + 1;
123 
124 	len = snprintf(data + total, 8192 - total, "%s=%d",
125 		       "MaxBurstLength", MaxBurstLength);
126 	total += len + 1;
127 
128 	len = snprintf(data + total, 8192 - total, "%s=%d",
129 		       "InitialR2T", initialR2T);
130 	total += len + 1;
131 
132 	/* add one extra NUL byte at the end to match real iSCSI params */
133 	total++;
134 
135 	/* store incoming parameters */
136 	rc = spdk_iscsi_parse_params(params_p, data, total, false, NULL);
137 	CU_ASSERT(rc == 0);
138 
139 	/* negotiate parameters */
140 	rc = spdk_iscsi_negotiate_params(&conn, params_p,
141 					 data, 8192, rc);
142 	CU_ASSERT(rc > 0);
143 
144 	rc = spdk_iscsi_copy_param2var(&conn);
145 	CU_ASSERT(rc == 0);
146 	CU_ASSERT(conn.sess->FirstBurstLength <= SPDK_ISCSI_FIRST_BURST_LENGTH);
147 	CU_ASSERT(conn.sess->FirstBurstLength <= conn.sess->MaxBurstLength);
148 	CU_ASSERT(conn.sess->MaxBurstLength <= SPDK_ISCSI_MAX_BURST_LENGTH);
149 	CU_ASSERT(conn.sess->MaxOutstandingR2T == 1);
150 
151 	spdk_iscsi_param_free(sess.params);
152 	spdk_iscsi_param_free(conn.params);
153 	spdk_iscsi_param_free(*params_p);
154 }
155 
156 static void
157 param_negotiation_test(void)
158 {
159 	burst_length_param_negotation(8192, 16384, 0);
160 	burst_length_param_negotation(8192, 16384, 1);
161 	burst_length_param_negotation(8192, 1024, 1);
162 	burst_length_param_negotation(8192, 1024, 0);
163 	burst_length_param_negotation(512, 1024, 1);
164 	burst_length_param_negotation(512, 1024, 0);
165 }
166 
167 static void
168 list_negotiation_test(void)
169 {
170 	int add_param_value = 0;
171 	struct iscsi_param param = {};
172 	char *new_val;
173 	char valid_list_buf[1024];
174 	char in_val_buf[1024];
175 
176 #define TEST_LIST(valid_list, in_val, expected_result) \
177 	do { \
178 		snprintf(valid_list_buf, sizeof(valid_list_buf), "%s", valid_list); \
179 		snprintf(in_val_buf, sizeof(in_val_buf), "%s", in_val); \
180 		new_val = spdk_iscsi_negotiate_param_list(&add_param_value, &param, valid_list_buf, in_val_buf, NULL); \
181 		if (expected_result) { \
182 			SPDK_CU_ASSERT_FATAL(new_val != NULL); \
183 			CU_ASSERT_STRING_EQUAL(new_val, expected_result); \
184 		} \
185 	} while (0)
186 
187 	TEST_LIST("None", "None", "None");
188 	TEST_LIST("CHAP,None", "None", "None");
189 	TEST_LIST("CHAP,None", "CHAP", "CHAP");
190 	TEST_LIST("KRB5,SRP,CHAP,None", "SRP,CHAP,None", "SRP");
191 	TEST_LIST("KRB5,SRP,CHAP,None", "CHAP,SRP,None", "CHAP");
192 	TEST_LIST("KRB5,SRP,CHAP,None", "SPKM1,SRP,CHAP,None", "SRP");
193 	TEST_LIST("KRB5,SRP,None", "CHAP,None", "None");
194 }
195 
196 #define PARSE(strconst, partial_enabled, partial_text) \
197 	data = strconst; \
198 	len = sizeof(strconst); \
199 	rc = spdk_iscsi_parse_params(&params, data, len, partial_enabled, partial_text)
200 
201 #define EXPECT_VAL(key, expected_value) \
202 	{ \
203 		const char *val = spdk_iscsi_param_get_val(params, key); \
204 		CU_ASSERT(val != NULL); \
205 		if (val != NULL) { \
206 			CU_ASSERT(strcmp(val, expected_value) == 0); \
207 		} \
208 	}
209 
210 #define EXPECT_NULL(key) \
211 	CU_ASSERT(spdk_iscsi_param_get_val(params, key) == NULL)
212 
213 static void
214 parse_valid_test(void)
215 {
216 	struct iscsi_param *params = NULL;
217 	int rc;
218 	char *data;
219 	int len;
220 	char *partial_parameter = NULL;
221 
222 	/* simple test with a single key=value */
223 	PARSE("Abc=def\0", false, NULL);
224 	CU_ASSERT(rc == 0);
225 	EXPECT_VAL("Abc", "def");
226 
227 	/* multiple key=value pairs */
228 	PARSE("Aaa=bbbbbb\0Xyz=test\0", false, NULL);
229 	CU_ASSERT(rc == 0);
230 	EXPECT_VAL("Aaa", "bbbbbb");
231 	EXPECT_VAL("Xyz", "test");
232 
233 	/* value with embedded '=' */
234 	PARSE("A=b=c\0", false, NULL);
235 	CU_ASSERT(rc == 0);
236 	EXPECT_VAL("A", "b=c");
237 
238 	/* CHAP_C=AAAA.... with value length 8192 */
239 	len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1/* null terminators */;
240 	data = malloc(len);
241 	SPDK_CU_ASSERT_FATAL(data != NULL);
242 	memset(data, 'A', len);
243 	memcpy(data, "CHAP_C", 6);
244 	data[6] = '=';
245 	data[len - 1] = '\0';
246 	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
247 	CU_ASSERT(rc == 0);
248 	free(data);
249 
250 	/* partial parameter: value is partial */
251 	PARSE("C=AAA\0D=B", true, &partial_parameter);
252 	SPDK_CU_ASSERT_FATAL(partial_parameter != NULL);
253 	CU_ASSERT_STRING_EQUAL(partial_parameter, "D=B");
254 	CU_ASSERT(rc == 0);
255 	EXPECT_VAL("C", "AAA");
256 	EXPECT_NULL("D");
257 	PARSE("XXXX\0E=UUUU\0", false, &partial_parameter);
258 	CU_ASSERT(rc == 0);
259 	EXPECT_VAL("D", "BXXXX");
260 	EXPECT_VAL("E", "UUUU");
261 	CU_ASSERT_PTR_NULL(partial_parameter);
262 
263 	/* partial parameter: key is partial */
264 	PARSE("IAMAFAK", true, &partial_parameter);
265 	CU_ASSERT_STRING_EQUAL(partial_parameter, "IAMAFAK");
266 	CU_ASSERT(rc == 0);
267 	EXPECT_NULL("IAMAFAK");
268 	PARSE("EDKEY=TTTT\0F=IIII", false, &partial_parameter);
269 	CU_ASSERT(rc == 0);
270 	EXPECT_VAL("IAMAFAKEDKEY", "TTTT");
271 	EXPECT_VAL("F", "IIII");
272 	CU_ASSERT_PTR_NULL(partial_parameter);
273 
274 	/* Second partial parameter is the only parameter */
275 	PARSE("OOOO", true, &partial_parameter);
276 	CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
277 	CU_ASSERT(rc == 0);
278 	EXPECT_NULL("OOOO");
279 	PARSE("LL=MMMM", false, &partial_parameter);
280 	CU_ASSERT(rc == 0);
281 	EXPECT_VAL("OOOOLL", "MMMM");
282 	CU_ASSERT_PTR_NULL(partial_parameter);
283 
284 	spdk_iscsi_param_free(params);
285 }
286 
287 static void
288 parse_invalid_test(void)
289 {
290 	struct iscsi_param *params = NULL;
291 	int rc;
292 	char *data;
293 	int len;
294 
295 	/* key without '=' */
296 	PARSE("Abc\0", false, NULL);
297 	CU_ASSERT(rc != 0);
298 	EXPECT_NULL("Abc");
299 
300 	/* multiple key=value pairs, one missing '=' */
301 	PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL);
302 	CU_ASSERT(rc != 0);
303 	EXPECT_VAL("Abc", "def");
304 	EXPECT_NULL("Xyz");
305 	EXPECT_NULL("Www");
306 
307 	/* empty key */
308 	PARSE("=abcdef", false, NULL);
309 	CU_ASSERT(rc != 0);
310 	EXPECT_NULL("");
311 
312 	/* CHAP_C=AAAA.... with value length 8192 + 1 */
313 	len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ +
314 	      1 /* null terminators */;
315 	data = malloc(len);
316 	SPDK_CU_ASSERT_FATAL(data != NULL);
317 	memset(data, 'A', len);
318 	memcpy(data, "CHAP_C", 6);
319 	data[6] = '=';
320 	data[len - 1] = '\0';
321 	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
322 	free(data);
323 	CU_ASSERT(rc != 0);
324 	EXPECT_NULL("CHAP_C");
325 
326 	/* Test simple value, length of value bigger than 255 */
327 	len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ +
328 	      1 /* null terminators */;
329 	data = malloc(len);
330 	SPDK_CU_ASSERT_FATAL(data != NULL);
331 	memset(data, 'A', len);
332 	data[1] = '=';
333 	data[len - 1] = '\0';
334 	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
335 	free(data);
336 	CU_ASSERT(rc != 0);
337 	EXPECT_NULL("A");
338 
339 	/* key length bigger than 63 */
340 	len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ +
341 	      1 /* null terminators */;
342 	data = malloc(len);
343 	SPDK_CU_ASSERT_FATAL(data != NULL);
344 	memset(data, 'A', len);
345 	data[64] = '=';
346 	data[len - 1] = '\0';
347 	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
348 	free(data);
349 	CU_ASSERT(rc != 0);
350 	EXPECT_NULL("A");
351 
352 	/* duplicated key */
353 	PARSE("B=BB", false, NULL);
354 	CU_ASSERT(rc == 0);
355 	PARSE("B=BBBB", false, NULL);
356 	CU_ASSERT(rc != 0);
357 	EXPECT_VAL("B", "BB");
358 
359 	spdk_iscsi_param_free(params);
360 }
361 
362 int
363 main(int argc, char **argv)
364 {
365 	CU_pSuite	suite = NULL;
366 	unsigned int	num_failures;
367 
368 	if (CU_initialize_registry() != CUE_SUCCESS) {
369 		return CU_get_error();
370 	}
371 
372 	suite = CU_add_suite("iscsi_suite", NULL, NULL);
373 	if (suite == NULL) {
374 		CU_cleanup_registry();
375 		return CU_get_error();
376 	}
377 
378 	if (
379 		CU_add_test(suite, "param negotiation test",
380 			    param_negotiation_test) == NULL ||
381 		CU_add_test(suite, "list negotation test",
382 			    list_negotiation_test) == NULL ||
383 		CU_add_test(suite, "parse valid test",
384 			    parse_valid_test) == NULL ||
385 		CU_add_test(suite, "parse invalid test",
386 			    parse_invalid_test) == NULL
387 	) {
388 		CU_cleanup_registry();
389 		return CU_get_error();
390 	}
391 
392 	CU_basic_set_mode(CU_BRM_VERBOSE);
393 	CU_basic_run_tests();
394 	num_failures = CU_get_number_of_failures();
395 	CU_cleanup_registry();
396 	return num_failures;
397 }
398