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 = ¶ms; 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, ¶m, 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); \ 192 rc = spdk_iscsi_parse_params(¶ms, 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(¶ms, 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 spdk_iscsi_param_free(params); 278 } 279 280 static void 281 parse_invalid_test(void) 282 { 283 struct iscsi_param *params = NULL; 284 int rc; 285 char *data; 286 int len; 287 288 /* key without '=' */ 289 PARSE("Abc\0", false, NULL); 290 CU_ASSERT(rc != 0); 291 EXPECT_NULL("Abc"); 292 293 /* multiple key=value pairs, one missing '=' */ 294 PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL); 295 CU_ASSERT(rc != 0); 296 EXPECT_VAL("Abc", "def"); 297 EXPECT_NULL("Xyz"); 298 EXPECT_NULL("Www"); 299 300 /* empty key */ 301 PARSE("=abcdef", false, NULL); 302 CU_ASSERT(rc != 0); 303 EXPECT_NULL(""); 304 305 /* CHAP_C=AAAA.... with value length 8192 + 1 */ 306 len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ + 307 1 /* null terminators */; 308 data = malloc(len); 309 SPDK_CU_ASSERT_FATAL(data != NULL); 310 memset(data, 'A', len); 311 memcpy(data, "CHAP_C", 6); 312 data[6] = '='; 313 data[len - 1] = '\0'; 314 rc = spdk_iscsi_parse_params(¶ms, data, len, false, NULL); 315 free(data); 316 CU_ASSERT(rc != 0); 317 EXPECT_NULL("CHAP_C"); 318 319 /* Test simple value, length of value bigger than 255 */ 320 len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ + 321 1 /* null terminators */; 322 data = malloc(len); 323 SPDK_CU_ASSERT_FATAL(data != NULL); 324 memset(data, 'A', len); 325 data[1] = '='; 326 data[len - 1] = '\0'; 327 rc = spdk_iscsi_parse_params(¶ms, data, len, false, NULL); 328 free(data); 329 CU_ASSERT(rc != 0); 330 EXPECT_NULL("A"); 331 332 /* key length bigger than 63 */ 333 len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ + 334 1 /* null terminators */; 335 data = malloc(len); 336 SPDK_CU_ASSERT_FATAL(data != NULL); 337 memset(data, 'A', len); 338 data[64] = '='; 339 data[len - 1] = '\0'; 340 rc = spdk_iscsi_parse_params(¶ms, data, len, false, NULL); 341 free(data); 342 CU_ASSERT(rc != 0); 343 EXPECT_NULL("A"); 344 345 /* duplicated key */ 346 PARSE("B=BB", false, NULL); 347 CU_ASSERT(rc == 0); 348 PARSE("B=BBBB", false, NULL); 349 CU_ASSERT(rc != 0); 350 EXPECT_VAL("B", "BB"); 351 352 spdk_iscsi_param_free(params); 353 } 354 355 int 356 main(int argc, char **argv) 357 { 358 CU_pSuite suite = NULL; 359 unsigned int num_failures; 360 361 if (CU_initialize_registry() != CUE_SUCCESS) { 362 return CU_get_error(); 363 } 364 365 suite = CU_add_suite("iscsi_suite", NULL, NULL); 366 if (suite == NULL) { 367 CU_cleanup_registry(); 368 return CU_get_error(); 369 } 370 371 if ( 372 CU_add_test(suite, "param negotiation test", 373 param_negotiation_test) == NULL || 374 CU_add_test(suite, "list negotiation test", 375 list_negotiation_test) == NULL || 376 CU_add_test(suite, "parse valid test", 377 parse_valid_test) == NULL || 378 CU_add_test(suite, "parse invalid test", 379 parse_invalid_test) == NULL 380 ) { 381 CU_cleanup_registry(); 382 return CU_get_error(); 383 } 384 385 CU_basic_set_mode(CU_BRM_VERBOSE); 386 CU_basic_run_tests(); 387 num_failures = CU_get_number_of_failures(); 388 CU_cleanup_registry(); 389 return num_failures; 390 } 391