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 = ¶ms; 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, ¶m, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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(¶ms, 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