diff --git a/Makefile.am b/Makefile.am index e505a37..1927f71 100644 --- a/Makefile.am +++ b/Makefile.am @@ -210,6 +210,7 @@ bin_iscsi_test_cu_SOURCES = test-tool/iscsi-test-cu.c \ test-tool/test_inquiry_version_descriptors.c \ test-tool/test_iscsi_cmdsn_toohigh.c \ test-tool/test_iscsi_cmdsn_toolow.c \ + test-tool/test_iscsi_datasn_invalid.c \ test-tool/test_mandatory_sbc.c \ test-tool/test_modesense6_all_pages.c \ test-tool/test_modesense6_residuals.c \ diff --git a/test-tool/iscsi-test-cu.c b/test-tool/iscsi-test-cu.c index 2742d3c..1b1ee71 100644 --- a/test-tool/iscsi-test-cu.c +++ b/test-tool/iscsi-test-cu.c @@ -458,6 +458,11 @@ static CU_TestInfo tests_iscsi_cmdsn[] = { CU_TEST_INFO_NULL }; +static CU_TestInfo tests_iscsi_datasn[] = { + { (char *)"iSCSIDataSnInvalid", test_iscsi_datasn_invalid }, + CU_TEST_INFO_NULL +}; + static CU_TestInfo tests_iscsi_residuals[] = { { (char *)"Read10Invalid", test_read10_invalid }, { (char *)"Read10Residuals", test_read10_residuals }, @@ -476,6 +481,8 @@ static CU_TestInfo tests_iscsi_residuals[] = { static libiscsi_suite_info iscsi_suites[] = { { "iSCSIcmdsn", NON_PGR_FUNCS, tests_iscsi_cmdsn }, + { "iSCSIdatasn", NON_PGR_FUNCS, + tests_iscsi_datasn }, { "iSCSIResiduals", NON_PGR_FUNCS, tests_iscsi_residuals }, { NULL, NULL, NULL, NULL, NULL, NULL } @@ -524,6 +531,7 @@ static libiscsi_suite_info all_suites[] = { { "WriteVerify12", NON_PGR_FUNCS, tests_writeverify12 }, { "WriteVerify16", NON_PGR_FUNCS, tests_writeverify16 }, { "iSCSIcmdsn", NON_PGR_FUNCS, tests_iscsi_cmdsn }, + { "iSCSIdatasn", NON_PGR_FUNCS, tests_iscsi_datasn }, { "iSCSIResiduals", NON_PGR_FUNCS, tests_iscsi_residuals }, { NULL, NULL, NULL, NULL, NULL, NULL }, }; diff --git a/test-tool/iscsi-test-cu.h b/test-tool/iscsi-test-cu.h index 80e6b73..51c9044 100644 --- a/test-tool/iscsi-test-cu.h +++ b/test-tool/iscsi-test-cu.h @@ -69,6 +69,8 @@ void test_inquiry_version_descriptors(void); void test_iscsi_cmdsn_toohigh(void); void test_iscsi_cmdsn_toolow(void); +void test_iscsi_datasn_invalid(void); + void test_mandatory_sbc(void); void test_modesense6_all_pages(void); diff --git a/test-tool/test_iscsi_datasn_invalid.c b/test-tool/test_iscsi_datasn_invalid.c new file mode 100644 index 0000000..8d58705 --- /dev/null +++ b/test-tool/test_iscsi_datasn_invalid.c @@ -0,0 +1,152 @@ +/* + Copyright (C) 2014 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include +#include + +#include "iscsi.h" +#include "iscsi-private.h" +#include "scsi-lowlevel.h" +#include "iscsi-test-cu.h" + +static int change_datasn; + +static int my_iscsi_queue_pdu(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu _U_) +{ + uint32_t datasn; + + if (pdu->outdata.data[0] != ISCSI_PDU_DATA_OUT) { + return 0; + } + switch (change_datasn) { + case 1: + /* change datasn to 0 */ + scsi_set_uint32(&pdu->outdata.data[36], 0); + break; + case 2: + /* change datasn to 27 */ + scsi_set_uint32(&pdu->outdata.data[36], 27); + break; + case 3: + /* change datasn to -1 */ + scsi_set_uint32(&pdu->outdata.data[36], -1); + break; + case 4: + /* change datasn from (0,1) to (1,0) */ + datasn = scsi_get_uint32(&pdu->outdata.data[36]); + scsi_set_uint32(&pdu->outdata.data[36], 1 - datasn); + break; + } + return 0; +} + +void test_iscsi_datasn_invalid(void) +{ + int ret; + unsigned char *buf = alloca(2 * block_size); + + CHECK_FOR_DATALOSS; + + logging(LOG_VERBOSE, LOG_BLANK_LINE); + logging(LOG_VERBOSE, "Test sending invalid iSCSI DATASN"); + + + logging(LOG_VERBOSE, "Send 2 DATAIN with DATASN==0. Should fail."); + change_datasn = 1; + + iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsic->target_max_recv_data_segment_length = block_size; + local_iscsi_queue_pdu = my_iscsi_queue_pdu; + iscsi_set_noautoreconnect(iscsic, 1); + iscsi_set_timeout(iscsic, 3); + + ret = write10(iscsic, tgt_lun, 100, 2 * block_size, + block_size, 0, 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] WRITE10 is not implemented."); + CU_PASS("WRITE10 is not implemented."); + return; + } + CU_ASSERT_NOT_EQUAL(ret, 0); + + iscsi_set_noautoreconnect(iscsic, 0); + + + logging(LOG_VERBOSE, "Send DATAIN with DATASN==27. Should fail"); + change_datasn = 2; + + iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsic->target_max_recv_data_segment_length = block_size; + local_iscsi_queue_pdu = my_iscsi_queue_pdu; + iscsi_set_noautoreconnect(iscsic, 1); + iscsi_set_timeout(iscsic, 3); + + ret = write10(iscsic, tgt_lun, 100, block_size, + block_size, 0, 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] WRITE10 is not implemented."); + CU_PASS("WRITE10 is not implemented."); + return; + } + CU_ASSERT_NOT_EQUAL(ret, 0); + + iscsi_set_noautoreconnect(iscsic, 0); + + + logging(LOG_VERBOSE, "Send DATAIN with DATASN==-1. Should fail"); + change_datasn = 3; + + iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsic->target_max_recv_data_segment_length = block_size; + local_iscsi_queue_pdu = my_iscsi_queue_pdu; + iscsi_set_noautoreconnect(iscsic, 1); + iscsi_set_timeout(iscsic, 3); + + ret = write10(iscsic, tgt_lun, 100, block_size, + block_size, 0, 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] WRITE10 is not implemented."); + CU_PASS("WRITE10 is not implemented."); + return; + } + CU_ASSERT_NOT_EQUAL(ret, 0); + + iscsi_set_noautoreconnect(iscsic, 0); + + + + logging(LOG_VERBOSE, "Send DATAIN in reverse order (datasn == 1,0). Should fail"); + change_datasn = 4; + + iscsic->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO; + iscsic->target_max_recv_data_segment_length = block_size; + local_iscsi_queue_pdu = my_iscsi_queue_pdu; + iscsi_set_noautoreconnect(iscsic, 1); + iscsi_set_timeout(iscsic, 3); + + ret = write10(iscsic, tgt_lun, 100, 2 * block_size, + block_size, 0, 0, 0, 0, 0, buf); + if (ret == -2) { + logging(LOG_NORMAL, "[SKIPPED] WRITE10 is not implemented."); + CU_PASS("WRITE10 is not implemented."); + return; + } + CU_ASSERT_NOT_EQUAL(ret, 0); + + iscsi_set_noautoreconnect(iscsic, 0); +}