xref: /spdk/test/unit/lib/iscsi/param.c/param_ut.c (revision 1fc4165fe9bf8512483356ad8e6d27f793f2e3db)
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  #include "spdk_internal/mock.h"
44  
45  struct spdk_iscsi_globals g_spdk_iscsi;
46  
47  DEFINE_STUB(spdk_iscsi_find_tgt_node, struct spdk_iscsi_tgt_node *,
48  	    (const char *target_name), NULL);
49  
50  DEFINE_STUB(spdk_iscsi_tgt_node_access, bool,
51  	    (struct spdk_iscsi_conn *conn, struct spdk_iscsi_tgt_node *target,
52  	     const char *iqn, const char *addr),
53  	    false);
54  
55  DEFINE_STUB(spdk_iscsi_send_tgts, int,
56  	    (struct spdk_iscsi_conn *conn, const char *iiqn, const char *iaddr,
57  	     const char *tiqn, uint8_t *data, int alloc_len, int data_len),
58  	    0);
59  
60  static void
61  burst_length_param_negotation(int FirstBurstLength, int MaxBurstLength,
62  			      int initialR2T)
63  {
64  	struct spdk_iscsi_sess sess;
65  	struct spdk_iscsi_conn conn;
66  	struct iscsi_param *params;
67  	struct iscsi_param **params_p;
68  	char data[8192];
69  	int rc;
70  	int total, len;
71  
72  	total = 0;
73  	params = NULL;
74  	params_p = &params;
75  
76  	memset(&sess, 0, sizeof(sess));
77  	memset(&conn, 0, sizeof(conn));
78  	memset(data, 0, 8192);
79  
80  	sess.ExpCmdSN = 0;
81  	sess.MaxCmdSN = 64;
82  	sess.session_type = SESSION_TYPE_NORMAL;
83  	sess.params = NULL;
84  	sess.MaxBurstLength = 65536;
85  	sess.InitialR2T = true;
86  	sess.FirstBurstLength = SPDK_ISCSI_FIRST_BURST_LENGTH;
87  	sess.MaxOutstandingR2T = 1;
88  
89  	/* set default params */
90  	rc = spdk_iscsi_sess_params_init(&sess.params);
91  	CU_ASSERT(rc == 0);
92  
93  	rc = spdk_iscsi_param_set_int(sess.params, "FirstBurstLength",
94  				      sess.FirstBurstLength);
95  	CU_ASSERT(rc == 0);
96  
97  	rc = spdk_iscsi_param_set_int(sess.params, "MaxBurstLength",
98  				      sess.MaxBurstLength);
99  	CU_ASSERT(rc == 0);
100  
101  	rc = spdk_iscsi_param_set(sess.params, "InitialR2T",
102  				  sess.InitialR2T ? "Yes" : "No");
103  	CU_ASSERT(rc == 0);
104  
105  	conn.full_feature = 1;
106  	conn.sess = &sess;
107  	conn.MaxRecvDataSegmentLength = 65536;
108  
109  	rc = spdk_iscsi_conn_params_init(&conn.params);
110  	CU_ASSERT(rc == 0);
111  
112  	/* construct the data */
113  	len = snprintf(data + total, 8192 - total, "%s=%d",
114  		       "FirstBurstLength", FirstBurstLength);
115  	total += len + 1;
116  
117  	len = snprintf(data + total, 8192 - total, "%s=%d",
118  		       "MaxBurstLength", MaxBurstLength);
119  	total += len + 1;
120  
121  	len = snprintf(data + total, 8192 - total, "%s=%d",
122  		       "InitialR2T", initialR2T);
123  	total += len + 1;
124  
125  	/* add one extra NUL byte at the end to match real iSCSI params */
126  	total++;
127  
128  	/* store incoming parameters */
129  	rc = spdk_iscsi_parse_params(params_p, data, total, false, NULL);
130  	CU_ASSERT(rc == 0);
131  
132  	/* negotiate parameters */
133  	rc = spdk_iscsi_negotiate_params(&conn, params_p,
134  					 data, 8192, rc);
135  	CU_ASSERT(rc > 0);
136  
137  	rc = spdk_iscsi_copy_param2var(&conn);
138  	CU_ASSERT(rc == 0);
139  	CU_ASSERT(conn.sess->FirstBurstLength <= SPDK_ISCSI_FIRST_BURST_LENGTH);
140  	CU_ASSERT(conn.sess->FirstBurstLength <= conn.sess->MaxBurstLength);
141  	CU_ASSERT(conn.sess->MaxBurstLength <= SPDK_ISCSI_MAX_BURST_LENGTH);
142  	CU_ASSERT(conn.sess->MaxOutstandingR2T == 1);
143  
144  	spdk_iscsi_param_free(sess.params);
145  	spdk_iscsi_param_free(conn.params);
146  	spdk_iscsi_param_free(*params_p);
147  }
148  
149  static void
150  param_negotiation_test(void)
151  {
152  	burst_length_param_negotation(8192, 16384, 0);
153  	burst_length_param_negotation(8192, 16384, 1);
154  	burst_length_param_negotation(8192, 1024, 1);
155  	burst_length_param_negotation(8192, 1024, 0);
156  	burst_length_param_negotation(512, 1024, 1);
157  	burst_length_param_negotation(512, 1024, 0);
158  }
159  
160  static void
161  list_negotiation_test(void)
162  {
163  	int add_param_value = 0;
164  	struct iscsi_param param = {};
165  	char *new_val;
166  	char valid_list_buf[1024];
167  	char in_val_buf[1024];
168  
169  #define TEST_LIST(valid_list, in_val, expected_result) \
170  	do { \
171  		snprintf(valid_list_buf, sizeof(valid_list_buf), "%s", valid_list); \
172  		snprintf(in_val_buf, sizeof(in_val_buf), "%s", in_val); \
173  		new_val = spdk_iscsi_negotiate_param_list(&add_param_value, &param, valid_list_buf, in_val_buf, NULL); \
174  		if (expected_result) { \
175  			SPDK_CU_ASSERT_FATAL(new_val != NULL); \
176  			CU_ASSERT_STRING_EQUAL(new_val, expected_result); \
177  		} \
178  	} while (0)
179  
180  	TEST_LIST("None", "None", "None");
181  	TEST_LIST("CHAP,None", "None", "None");
182  	TEST_LIST("CHAP,None", "CHAP", "CHAP");
183  	TEST_LIST("KRB5,SRP,CHAP,None", "SRP,CHAP,None", "SRP");
184  	TEST_LIST("KRB5,SRP,CHAP,None", "CHAP,SRP,None", "CHAP");
185  	TEST_LIST("KRB5,SRP,CHAP,None", "SPKM1,SRP,CHAP,None", "SRP");
186  	TEST_LIST("KRB5,SRP,None", "CHAP,None", "None");
187  }
188  
189  #define PARSE(strconst, partial_enabled, partial_text) \
190  	data = strconst; \
191  	len = sizeof(strconst) - 1; \
192  	rc = spdk_iscsi_parse_params(&params, data, len, partial_enabled, partial_text)
193  
194  #define EXPECT_VAL(key, expected_value) \
195  	{ \
196  		const char *val = spdk_iscsi_param_get_val(params, key); \
197  		CU_ASSERT(val != NULL); \
198  		if (val != NULL) { \
199  			CU_ASSERT(strcmp(val, expected_value) == 0); \
200  		} \
201  	}
202  
203  #define EXPECT_NULL(key) \
204  	CU_ASSERT(spdk_iscsi_param_get_val(params, key) == NULL)
205  
206  static void
207  parse_valid_test(void)
208  {
209  	struct iscsi_param *params = NULL;
210  	int rc;
211  	char *data;
212  	int len;
213  	char *partial_parameter = NULL;
214  
215  	/* simple test with a single key=value */
216  	PARSE("Abc=def\0", false, NULL);
217  	CU_ASSERT(rc == 0);
218  	EXPECT_VAL("Abc", "def");
219  
220  	/* multiple key=value pairs */
221  	PARSE("Aaa=bbbbbb\0Xyz=test\0", false, NULL);
222  	CU_ASSERT(rc == 0);
223  	EXPECT_VAL("Aaa", "bbbbbb");
224  	EXPECT_VAL("Xyz", "test");
225  
226  	/* value with embedded '=' */
227  	PARSE("A=b=c\0", false, NULL);
228  	CU_ASSERT(rc == 0);
229  	EXPECT_VAL("A", "b=c");
230  
231  	/* CHAP_C=AAAA.... with value length 8192 */
232  	len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1/* null terminators */;
233  	data = malloc(len);
234  	SPDK_CU_ASSERT_FATAL(data != NULL);
235  	memset(data, 'A', len);
236  	memcpy(data, "CHAP_C", 6);
237  	data[6] = '=';
238  	data[len - 1] = '\0';
239  	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
240  	CU_ASSERT(rc == 0);
241  	free(data);
242  
243  	/* partial parameter: value is partial */
244  	PARSE("C=AAA\0D=B", true, &partial_parameter);
245  	SPDK_CU_ASSERT_FATAL(partial_parameter != NULL);
246  	CU_ASSERT_STRING_EQUAL(partial_parameter, "D=B");
247  	CU_ASSERT(rc == 0);
248  	EXPECT_VAL("C", "AAA");
249  	EXPECT_NULL("D");
250  	PARSE("XXXX\0E=UUUU\0", false, &partial_parameter);
251  	CU_ASSERT(rc == 0);
252  	EXPECT_VAL("D", "BXXXX");
253  	EXPECT_VAL("E", "UUUU");
254  	CU_ASSERT_PTR_NULL(partial_parameter);
255  
256  	/* partial parameter: key is partial */
257  	PARSE("IAMAFAK", true, &partial_parameter);
258  	CU_ASSERT_STRING_EQUAL(partial_parameter, "IAMAFAK");
259  	CU_ASSERT(rc == 0);
260  	EXPECT_NULL("IAMAFAK");
261  	PARSE("EDKEY=TTTT\0F=IIII", false, &partial_parameter);
262  	CU_ASSERT(rc == 0);
263  	EXPECT_VAL("IAMAFAKEDKEY", "TTTT");
264  	EXPECT_VAL("F", "IIII");
265  	CU_ASSERT_PTR_NULL(partial_parameter);
266  
267  	/* Second partial parameter is the only parameter */
268  	PARSE("OOOO", true, &partial_parameter);
269  	CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
270  	CU_ASSERT(rc == 0);
271  	EXPECT_NULL("OOOO");
272  	PARSE("LL=MMMM", false, &partial_parameter);
273  	CU_ASSERT(rc == 0);
274  	EXPECT_VAL("OOOOLL", "MMMM");
275  	CU_ASSERT_PTR_NULL(partial_parameter);
276  
277  	partial_parameter = NULL;
278  	data = "PartialKey=";
279  	len = 7;
280  	rc = spdk_iscsi_parse_params(&params, data, len, true, &partial_parameter);
281  	CU_ASSERT(rc == 0);
282  	CU_ASSERT_STRING_EQUAL(partial_parameter, "Partial");
283  	EXPECT_NULL("PartialKey");
284  	PARSE("Key=Value", false, &partial_parameter);
285  	CU_ASSERT(rc == 0);
286  	EXPECT_VAL("PartialKey", "Value");
287  	CU_ASSERT_PTR_NULL(partial_parameter);
288  
289  	spdk_iscsi_param_free(params);
290  }
291  
292  static void
293  parse_invalid_test(void)
294  {
295  	struct iscsi_param *params = NULL;
296  	int rc;
297  	char *data;
298  	int len;
299  
300  	/* key without '=' */
301  	PARSE("Abc\0", false, NULL);
302  	CU_ASSERT(rc != 0);
303  	EXPECT_NULL("Abc");
304  
305  	/* multiple key=value pairs, one missing '=' */
306  	PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL);
307  	CU_ASSERT(rc != 0);
308  	EXPECT_VAL("Abc", "def");
309  	EXPECT_NULL("Xyz");
310  	EXPECT_NULL("Www");
311  
312  	/* empty key */
313  	PARSE("=abcdef", false, NULL);
314  	CU_ASSERT(rc != 0);
315  	EXPECT_NULL("");
316  
317  	/* CHAP_C=AAAA.... with value length 8192 + 1 */
318  	len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ +
319  	      1 /* null terminators */;
320  	data = malloc(len);
321  	SPDK_CU_ASSERT_FATAL(data != NULL);
322  	memset(data, 'A', len);
323  	memcpy(data, "CHAP_C", 6);
324  	data[6] = '=';
325  	data[len - 1] = '\0';
326  	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
327  	free(data);
328  	CU_ASSERT(rc != 0);
329  	EXPECT_NULL("CHAP_C");
330  
331  	/* Test simple value, length of value bigger than 255 */
332  	len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ +
333  	      1 /* null terminators */;
334  	data = malloc(len);
335  	SPDK_CU_ASSERT_FATAL(data != NULL);
336  	memset(data, 'A', len);
337  	data[1] = '=';
338  	data[len - 1] = '\0';
339  	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
340  	free(data);
341  	CU_ASSERT(rc != 0);
342  	EXPECT_NULL("A");
343  
344  	/* key length bigger than 63 */
345  	len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ +
346  	      1 /* null terminators */;
347  	data = malloc(len);
348  	SPDK_CU_ASSERT_FATAL(data != NULL);
349  	memset(data, 'A', len);
350  	data[64] = '=';
351  	data[len - 1] = '\0';
352  	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
353  	free(data);
354  	CU_ASSERT(rc != 0);
355  	EXPECT_NULL("A");
356  
357  	/* duplicated key */
358  	PARSE("B=BB", false, NULL);
359  	CU_ASSERT(rc == 0);
360  	PARSE("B=BBBB", false, NULL);
361  	CU_ASSERT(rc != 0);
362  	EXPECT_VAL("B", "BB");
363  
364  	/* Test where data buffer has non-NULL characters past the end of
365  	 * the valid data region.  This can happen with SPDK iSCSI target,
366  	 * since data buffers are reused and we do not zero the data buffers
367  	 * after they are freed since it would be too expensive.  Added as
368  	 * part of fixing an intermittent Calsoft failure that triggered this
369  	 * bug.
370  	 */
371  	data = "MaxRecvDataSegmentLength=81928";
372  	len = strlen(data) - 1;
373  	rc = spdk_iscsi_parse_params(&params, data, len, false, NULL);
374  	EXPECT_VAL("MaxRecvDataSegmentLength", "8192");
375  	CU_ASSERT(rc == 0);
376  	spdk_iscsi_param_free(params);
377  }
378  
379  int
380  main(int argc, char **argv)
381  {
382  	CU_pSuite	suite = NULL;
383  	unsigned int	num_failures;
384  
385  	if (CU_initialize_registry() != CUE_SUCCESS) {
386  		return CU_get_error();
387  	}
388  
389  	suite = CU_add_suite("iscsi_suite", NULL, NULL);
390  	if (suite == NULL) {
391  		CU_cleanup_registry();
392  		return CU_get_error();
393  	}
394  
395  	if (
396  		CU_add_test(suite, "param negotiation test",
397  			    param_negotiation_test) == NULL ||
398  		CU_add_test(suite, "list negotiation test",
399  			    list_negotiation_test) == NULL ||
400  		CU_add_test(suite, "parse valid test",
401  			    parse_valid_test) == NULL ||
402  		CU_add_test(suite, "parse invalid test",
403  			    parse_invalid_test) == NULL
404  	) {
405  		CU_cleanup_registry();
406  		return CU_get_error();
407  	}
408  
409  	CU_basic_set_mode(CU_BRM_VERBOSE);
410  	CU_basic_run_tests();
411  	num_failures = CU_get_number_of_failures();
412  	CU_cleanup_registry();
413  	return num_failures;
414  }
415