Skip to content
This repository
tree: 641027283b
Fetching contributors…

Cannot retrieve contributors at this time

file 204 lines (176 sloc) 5.908 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/*
Copyright (C) 2012 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <arpa/inet.h>
#include "iscsi.h"
#include "iscsi-private.h"
#include "scsi-lowlevel.h"
#include "iscsi-test.h"

static int change_bufferoffset;

uint32_t block_size;

static int my_iscsi_queue_pdu(struct iscsi_context *iscsi _U_, struct iscsi_pdu *pdu)
{
if (pdu->outdata.data[0] != ISCSI_PDU_DATA_OUT) {
return 0;
}
switch (change_bufferoffset) {
case 1:
/* Add 1M to the buffer offset */
*(uint32_t *)&pdu->outdata.data[40] = htonl(ntohl(*(uint32_t *)&pdu->outdata.data[40]) + 1024*1024);
break;
case 2:
/* Add -'block_size' to the buffer offset */
*(uint32_t *)&pdu->outdata.data[40] = htonl(ntohl(*(uint32_t *)&pdu->outdata.data[40]) - block_size);
break;
}
return 0;
}

static void test_cb(struct iscsi_context *iscsi _U_, int status,
void *command_data _U_, void *private_data)
{
struct scsi_task *task = command_data;
struct iscsi_async_state *state = private_data;

state->finished = 1;
state->status = status;

if (status) {
task->status = status;
}
}


int T1020_bufferoffset_invalid(const char *initiator, const char *url, int data_loss, int show_info)
{
struct iscsi_context *iscsi;
struct scsi_task *task;
struct scsi_readcapacity16 *rc16;
int ret, lun;
unsigned char data[block_size * 256];
struct iscsi_async_state test_state;

printf("1020_bufferoffset_invalid:\n");
printf("==========================\n");
if (show_info) {
printf("Test sending commands with invalid bufferoffset values.\n");
printf("We negotiate both DataPDUInOrder and DataSequenceInOrder so BufferOffset must be in sequence both within and across multiple sequences\n");
printf("1, Test that BufferOffset==1M too high is an error\n");
printf("2, Test that BufferOffset==-'block_size' is an error\n");
printf("\n");
return 0;
}

iscsi = iscsi_context_login(initiator, url, &lun);
if (iscsi == NULL) {
printf("Failed to login to target\n");
return -1;
}

/* find the size of the LUN */
task = iscsi_readcapacity16_sync(iscsi, lun);
if (task == NULL) {
printf("Failed to send READCAPACITY16 command: %s\n", iscsi_get_error(iscsi));
ret = -1;
goto finished;
}
if (task->status != SCSI_STATUS_GOOD) {
printf("READCAPACITY16 command: failed with sense. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
rc16 = scsi_datain_unmarshall(task);
if (rc16 == NULL) {
printf("failed to unmarshall READCAPACITY16 data. %s\n", iscsi_get_error(iscsi));
ret = -1;
scsi_free_scsi_task(task);
goto finished;
}
block_size = rc16->block_length;
scsi_free_scsi_task(task);


if (!data_loss) {
printf("--dataloss flag is not set. Skipping test\n");
ret = -2;
goto finished;
}


ret = 0;

iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
iscsi->target_max_recv_data_segment_length = block_size;
local_iscsi_queue_pdu = my_iscsi_queue_pdu;

printf("Write 2 DATA-IN with BUFFEROFFSET 1M too high ... ");
/* we dont want autoreconnect since some targets will drop the
* on this condition.
*/
iscsi_set_noautoreconnect(iscsi, 1);

task = iscsi_write10_task(iscsi, lun, 0, data, 2 * block_size, block_size,
0, 0, 0, 0, 0,
test_cb, &test_state);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send WRITE10 command: %s\n", iscsi_get_error(iscsi));
ret++;
goto test2;
}
change_bufferoffset = 1;
test_state.task = task;
test_state.finished = 0;
test_state.status = 0;
wait_until_test_finished(iscsi, &test_state);
change_bufferoffset = 0;
if (task->status == SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("WRITE10 command successful. Should have failed with error\n");
ret++;
scsi_free_scsi_task(task);
goto test2;
}
scsi_free_scsi_task(task);
printf("[OK]\n");

test2:
/* in case the previous test failed the session */
iscsi_set_noautoreconnect(iscsi, 0);
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
iscsi->target_max_recv_data_segment_length = block_size;

printf("Write 2 DATA-IN with BUFFEROFFSET==-%d ... ", block_size);
/* we dont want autoreconnect since some targets will drop the
* on this condition.
*/
iscsi_set_noautoreconnect(iscsi, 1);

task = iscsi_write10_task(iscsi, lun, 0, data, 2 * block_size, block_size,
0, 0, 0, 0, 0,
test_cb, &test_state);
if (task == NULL) {
printf("[FAILED]\n");
printf("Failed to send WRITE10 command: %s\n", iscsi_get_error(iscsi));
ret++;
goto test3;
}
change_bufferoffset = 2;
test_state.task = task;
test_state.finished = 0;
test_state.status = 0;
wait_until_test_finished(iscsi, &test_state);
change_bufferoffset = 0;
if (task->status == SCSI_STATUS_GOOD) {
printf("[FAILED]\n");
printf("WRITE10 command successful. Should have failed with error\n");
ret++;
scsi_free_scsi_task(task);
goto test3;
}
scsi_free_scsi_task(task);
printf("[OK]\n");


test3:
/* in case the previous test failed the session */
iscsi_set_noautoreconnect(iscsi, 0);
iscsi->use_immediate_data = ISCSI_IMMEDIATE_DATA_NO;
iscsi->target_max_recv_data_segment_length = block_size;

finished:
local_iscsi_queue_pdu = NULL;
iscsi_destroy_context(iscsi);
return ret;
}
Something went wrong with that request. Please try again.