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_iscsi; 46 47 DEFINE_STUB(iscsi_find_tgt_node, struct spdk_iscsi_tgt_node *, 48 (const char *target_name), NULL); 49 50 DEFINE_STUB(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(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_negotiation(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 = iscsi_sess_params_init(&sess.params); 91 CU_ASSERT(rc == 0); 92 93 rc = iscsi_param_set_int(sess.params, "FirstBurstLength", 94 sess.FirstBurstLength); 95 CU_ASSERT(rc == 0); 96 97 rc = iscsi_param_set_int(sess.params, "MaxBurstLength", 98 sess.MaxBurstLength); 99 CU_ASSERT(rc == 0); 100 101 rc = 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 = 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 = iscsi_parse_params(params_p, data, total, false, NULL); 130 CU_ASSERT(rc == 0); 131 132 /* negotiate parameters */ 133 rc = iscsi_negotiate_params(&conn, params_p, 134 data, 8192, rc); 135 CU_ASSERT(rc > 0); 136 137 rc = 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 iscsi_param_free(sess.params); 145 iscsi_param_free(conn.params); 146 iscsi_param_free(*params_p); 147 } 148 149 static void 150 param_negotiation_test(void) 151 { 152 burst_length_param_negotiation(8192, 16384, 0); 153 burst_length_param_negotiation(8192, 16384, 1); 154 burst_length_param_negotiation(8192, 1024, 1); 155 burst_length_param_negotiation(8192, 1024, 0); 156 burst_length_param_negotiation(512, 1024, 1); 157 burst_length_param_negotiation(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 = 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) - 1; \ 192 rc = iscsi_parse_params(¶ms, data, len, partial_enabled, partial_text) 193 194 #define EXPECT_VAL(key, expected_value) \ 195 { \ 196 const char *val = 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(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 = 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 /* partial parameter: NULL data */ 268 /* It is technically allowed to have a TEXT PDU with no data, yet 269 * CONTINUE bit is enabled - make sure we handle that case correctly. 270 */ 271 rc = iscsi_parse_params(¶ms, NULL, 0, true, &partial_parameter); 272 CU_ASSERT(rc == 0); 273 CU_ASSERT_PTR_NULL(partial_parameter); 274 275 /* Second partial parameter is the only parameter */ 276 PARSE("OOOO", true, &partial_parameter); 277 CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO"); 278 CU_ASSERT(rc == 0); 279 EXPECT_NULL("OOOO"); 280 PARSE("LL=MMMM", false, &partial_parameter); 281 CU_ASSERT(rc == 0); 282 EXPECT_VAL("OOOOLL", "MMMM"); 283 CU_ASSERT_PTR_NULL(partial_parameter); 284 285 partial_parameter = NULL; 286 data = "PartialKey="; 287 len = 7; 288 rc = iscsi_parse_params(¶ms, data, len, true, &partial_parameter); 289 CU_ASSERT(rc == 0); 290 CU_ASSERT_STRING_EQUAL(partial_parameter, "Partial"); 291 EXPECT_NULL("PartialKey"); 292 PARSE("Key=Value", false, &partial_parameter); 293 CU_ASSERT(rc == 0); 294 EXPECT_VAL("PartialKey", "Value"); 295 CU_ASSERT_PTR_NULL(partial_parameter); 296 297 iscsi_param_free(params); 298 } 299 300 static void 301 parse_invalid_test(void) 302 { 303 struct iscsi_param *params = NULL; 304 int rc; 305 char *data; 306 int len; 307 308 /* key without '=' */ 309 PARSE("Abc\0", false, NULL); 310 CU_ASSERT(rc != 0); 311 EXPECT_NULL("Abc"); 312 313 /* multiple key=value pairs, one missing '=' */ 314 PARSE("Abc=def\0Xyz\0Www=test\0", false, NULL); 315 CU_ASSERT(rc != 0); 316 EXPECT_VAL("Abc", "def"); 317 EXPECT_NULL("Xyz"); 318 EXPECT_NULL("Www"); 319 320 /* empty key */ 321 PARSE("=abcdef", false, NULL); 322 CU_ASSERT(rc != 0); 323 EXPECT_NULL(""); 324 325 /* CHAP_C=AAAA.... with value length 8192 + 1 */ 326 len = strlen("CHAP_C=") + ISCSI_TEXT_MAX_VAL_LEN + 1 /* max value len + 1 */ + 327 1 /* null terminators */; 328 data = malloc(len); 329 SPDK_CU_ASSERT_FATAL(data != NULL); 330 memset(data, 'A', len); 331 memcpy(data, "CHAP_C", 6); 332 data[6] = '='; 333 data[len - 1] = '\0'; 334 rc = iscsi_parse_params(¶ms, data, len, false, NULL); 335 free(data); 336 CU_ASSERT(rc != 0); 337 EXPECT_NULL("CHAP_C"); 338 339 /* Test simple value, length of value bigger than 255 */ 340 len = strlen("A=") + ISCSI_TEXT_MAX_SIMPLE_VAL_LEN + 1 /* max simple value len + 1 */ + 341 1 /* null terminators */; 342 data = malloc(len); 343 SPDK_CU_ASSERT_FATAL(data != NULL); 344 memset(data, 'A', len); 345 data[1] = '='; 346 data[len - 1] = '\0'; 347 rc = iscsi_parse_params(¶ms, data, len, false, NULL); 348 free(data); 349 CU_ASSERT(rc != 0); 350 EXPECT_NULL("A"); 351 352 /* key length bigger than 63 */ 353 len = ISCSI_TEXT_MAX_KEY_LEN + 1 /* max key length + 1 */ + 1 /* = */ + 1 /* A */ + 354 1 /* null terminators */; 355 data = malloc(len); 356 SPDK_CU_ASSERT_FATAL(data != NULL); 357 memset(data, 'A', len); 358 data[64] = '='; 359 data[len - 1] = '\0'; 360 rc = iscsi_parse_params(¶ms, data, len, false, NULL); 361 free(data); 362 CU_ASSERT(rc != 0); 363 EXPECT_NULL("A"); 364 365 /* duplicated key */ 366 PARSE("B=BB", false, NULL); 367 CU_ASSERT(rc == 0); 368 PARSE("B=BBBB", false, NULL); 369 CU_ASSERT(rc != 0); 370 EXPECT_VAL("B", "BB"); 371 372 /* Test where data buffer has non-NULL characters past the end of 373 * the valid data region. This can happen with SPDK iSCSI target, 374 * since data buffers are reused and we do not zero the data buffers 375 * after they are freed since it would be too expensive. Added as 376 * part of fixing an intermittent Calsoft failure that triggered this 377 * bug. 378 */ 379 data = "MaxRecvDataSegmentLength=81928"; 380 len = strlen(data) - 1; 381 rc = iscsi_parse_params(¶ms, data, len, false, NULL); 382 EXPECT_VAL("MaxRecvDataSegmentLength", "8192"); 383 CU_ASSERT(rc == 0); 384 iscsi_param_free(params); 385 } 386 387 int 388 main(int argc, char **argv) 389 { 390 CU_pSuite suite = NULL; 391 unsigned int num_failures; 392 393 CU_set_error_action(CUEA_ABORT); 394 CU_initialize_registry(); 395 396 suite = CU_add_suite("iscsi_suite", NULL, NULL); 397 398 CU_ADD_TEST(suite, param_negotiation_test); 399 CU_ADD_TEST(suite, list_negotiation_test); 400 CU_ADD_TEST(suite, parse_valid_test); 401 CU_ADD_TEST(suite, parse_invalid_test); 402 403 CU_basic_set_mode(CU_BRM_VERBOSE); 404 CU_basic_run_tests(); 405 num_failures = CU_get_number_of_failures(); 406 CU_cleanup_registry(); 407 return num_failures; 408 } 409