Input processing:

Input processing used to keep all data in one single input buffer, which
makes it hard to handle nested events as well as reading directly from the
socket into the application buffer without an extra copy.

Create a new iscsi_in_pdu structure where we store the header, and any data
for the recevied pdu and store them in a proper input queue.

Change the signature for all processing functions to tahe a iscsi_in_pdu
structure for the received pdu instead of just a pointer to a buffer.
This commit is contained in:
Ronnie Sahlberg
2010-12-11 15:15:51 +11:00
parent 8a6665a092
commit 1c024d6bc4
8 changed files with 172 additions and 148 deletions

View File

@@ -21,6 +21,25 @@
#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
#endif
#define ISCSI_RAW_HEADER_SIZE 48
#define ISCSI_DIGEST_SIZE 4
#define ISCSI_HEADER_SIZE (ISCSI_RAW_HEADER_SIZE \
+ (iscsi->header_digest == ISCSI_HEADER_DIGEST_NONE?0:ISCSI_DIGEST_SIZE))
struct iscsi_in_pdu {
struct iscsi_in_pdu *next;
long long hdr_pos;
unsigned char hdr[ISCSI_RAW_HEADER_SIZE + ISCSI_DIGEST_SIZE];
long long data_pos;
unsigned char *data;
};
void iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in);
void iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue);
struct iscsi_context {
const char *initiator_name;
const char *target_name;
@@ -45,16 +64,10 @@ struct iscsi_context {
struct iscsi_pdu *outqueue;
struct iscsi_pdu *waitpdu;
int insize;
int inpos;
unsigned char *inbuf;
struct iscsi_in_pdu *incoming;
struct iscsi_in_pdu *inqueue;
};
#define ISCSI_RAW_HEADER_SIZE 48
#define ISCSI_HEADER_SIZE (ISCSI_RAW_HEADER_SIZE \
+ (iscsi->header_digest == ISCSI_HEADER_DIGEST_NONE?0:4))
#define ISCSI_PDU_IMMEDIATE 0x40
#define ISCSI_PDU_TEXT_FINAL 0x80
@@ -139,29 +152,28 @@ int iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data,
struct scsi_task;
void iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task);
int iscsi_get_pdu_size(struct iscsi_context *iscsi, const unsigned char *hdr);
int iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
int size);
int iscsi_get_pdu_data_size(const unsigned char *hdr);
int iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in);
int iscsi_process_login_reply(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size);
struct iscsi_in_pdu *in);
int iscsi_process_text_reply(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size);
struct iscsi_in_pdu *in);
int iscsi_process_logout_reply(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size);
struct iscsi_in_pdu *in);
int iscsi_process_scsi_reply(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size);
struct iscsi_in_pdu *in);
int iscsi_process_scsi_data_in(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size,
struct iscsi_in_pdu *in,
int *is_finished);
int iscsi_process_nop_out_reply(struct iscsi_context *iscsi,
struct iscsi_pdu *pdu,
const unsigned char *hdr, int size);
struct iscsi_in_pdu *in);
void iscsi_set_error(struct iscsi_context *iscsi, const char *error_string,
...);

View File

@@ -94,27 +94,25 @@ iscsi_free_discovery_addresses(struct iscsi_discovery_address *addresses)
int
iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr, int size)
struct iscsi_in_pdu *in)
{
struct iscsi_discovery_address *targets = NULL;
unsigned char *ptr = in->data;
int size = in->data_pos;
/* verify the response looks sane */
if (hdr[1] != ISCSI_PDU_TEXT_FINAL) {
if (in->hdr[1] != ISCSI_PDU_TEXT_FINAL) {
iscsi_set_error(iscsi, "unsupported flags in text "
"reply %02x", hdr[1]);
"reply %02x", in->hdr[1]);
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
pdu->private_data);
return -1;
}
/* skip past the header */
hdr += ISCSI_HEADER_SIZE;
size -= ISCSI_HEADER_SIZE;
while (size > 0) {
int len;
len = strlen((char *)hdr);
len = strlen((char *)ptr);
if (len == 0) {
break;
@@ -130,7 +128,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
/* parse the strings */
if (!strncmp((char *)hdr, "TargetName=", 11)) {
if (!strncmp((char *)ptr, "TargetName=", 11)) {
struct iscsi_discovery_address *target;
target = malloc(sizeof(struct iscsi_discovery_address));
@@ -144,7 +142,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
return -1;
}
bzero(target, sizeof(struct iscsi_discovery_address));
target->target_name = strdup((char *)hdr+11);
target->target_name = strdup((char *)ptr+11);
if (target->target_name == NULL) {
iscsi_set_error(iscsi, "Failed to allocate "
"data for new discovered "
@@ -158,8 +156,8 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
target->next = targets;
targets = target;
} else if (!strncmp((char *)hdr, "TargetAddress=", 14)) {
targets->target_address = strdup((char *)hdr+14);
} else if (!strncmp((char *)ptr, "TargetAddress=", 14)) {
targets->target_address = strdup((char *)ptr+14);
if (targets->target_address == NULL) {
iscsi_set_error(iscsi, "Failed to allocate "
"data for new discovered "
@@ -171,14 +169,14 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
} else {
iscsi_set_error(iscsi, "Dont know how to handle "
"discovery string : %s", hdr);
"discovery string : %s", ptr);
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
pdu->private_data);
iscsi_free_discovery_addresses(targets);
return -1;
}
hdr += len + 1;
ptr += len + 1;
size -= len + 1;
}

View File

@@ -143,11 +143,11 @@ iscsi_destroy_context(struct iscsi_context *iscsi)
free(discard_const(iscsi->alias));
iscsi->alias = NULL;
if (iscsi->inbuf != NULL) {
free(iscsi->inbuf);
iscsi->inbuf = NULL;
iscsi->insize = 0;
iscsi->inpos = 0;
if (iscsi->incoming != NULL) {
iscsi_free_iscsi_in_pdu(iscsi->incoming);
}
if (iscsi->inqueue != NULL) {
iscsi_free_iscsi_inqueue(iscsi->inqueue);
}
free(iscsi->error_string);
@@ -205,3 +205,5 @@ iscsi_is_logged_in(struct iscsi_context *iscsi)
{
return iscsi->is_loggedin;
}

View File

@@ -245,9 +245,11 @@ iscsi_login_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
int
iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr, int size)
struct iscsi_in_pdu *in)
{
int status;
unsigned char *ptr = in->data;
int size = in->data_pos;
if (size < ISCSI_HEADER_SIZE) {
iscsi_set_error(iscsi, "dont have enough data to read status "
@@ -255,28 +257,25 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
return -1;
}
status = ntohs(*(uint16_t *)&hdr[36]);
status = ntohs(*(uint16_t *)&in->hdr[36]);
if (status != 0) {
pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
pdu->private_data);
return 0;
}
iscsi->statsn = ntohs(*(uint16_t *)&hdr[24]);
iscsi->statsn = ntohs(*(uint16_t *)&in->hdr[24]);
/* XXX here we should parse the data returned in case the target
* renegotiated some some parameters.
* we should also do proper handshaking if the target is not yet
* prepared to transition to the next stage
*/
/* skip past the header */
hdr += ISCSI_HEADER_SIZE;
size -= ISCSI_HEADER_SIZE;
while (size > 0) {
int len;
len = strlen((char *)hdr);
len = strlen((char *)ptr);
if (len == 0) {
break;
@@ -291,8 +290,8 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
/* parse the strings */
if (!strncmp((char *)hdr, "HeaderDigest=", 13)) {
if (!strcmp((char *)hdr + 13, "CRC32C")) {
if (!strncmp((char *)ptr, "HeaderDigest=", 13)) {
if (!strcmp((char *)ptr + 13, "CRC32C")) {
iscsi->header_digest
= ISCSI_HEADER_DIGEST_CRC32C;
} else {
@@ -301,7 +300,7 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
}
hdr += len + 1;
ptr += len + 1;
size -= len + 1;
}
@@ -354,7 +353,7 @@ iscsi_logout_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
int
iscsi_process_logout_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr _U_, int size _U_)
struct iscsi_in_pdu *in _U_)
{
iscsi->is_loggedin = 0;
pdu->callback(iscsi, SCSI_STATUS_GOOD, NULL, pdu->private_data);

View File

@@ -73,16 +73,16 @@ iscsi_nop_out_async(struct iscsi_context *iscsi, iscsi_command_cb cb,
int
iscsi_process_nop_out_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr, int size)
struct iscsi_in_pdu *in)
{
struct iscsi_data data;
data.data = NULL;
data.size = 0;
if (size > ISCSI_HEADER_SIZE) {
data.data = discard_const(&hdr[ISCSI_HEADER_SIZE]);
data.size = size - ISCSI_HEADER_SIZE;
if (in->data_pos > ISCSI_HEADER_SIZE) {
data.data = in->data;
data.size = in->data_pos;
}
pdu->callback(iscsi, SCSI_STATUS_GOOD, &data, pdu->private_data);

View File

@@ -158,11 +158,11 @@ iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
}
int
iscsi_get_pdu_size(struct iscsi_context *iscsi, const unsigned char *hdr)
iscsi_get_pdu_data_size(const unsigned char *hdr)
{
int size;
size = (ntohl(*(uint32_t *)&hdr[4])&0x00ffffff) + ISCSI_HEADER_SIZE;
size = (ntohl(*(uint32_t *)&hdr[4])&0x00ffffff);
size = (size+3)&0xfffffffc;
return size;
@@ -170,17 +170,16 @@ iscsi_get_pdu_size(struct iscsi_context *iscsi, const unsigned char *hdr)
int
iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
int size)
iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
{
uint32_t itt;
enum iscsi_opcode opcode;
struct iscsi_pdu *pdu;
uint8_t ahslen;
opcode = hdr[0] & 0x3f;
ahslen = hdr[4];
itt = ntohl(*(uint32_t *)&hdr[16]);
opcode = in->hdr[0] & 0x3f;
ahslen = in->hdr[4];
itt = ntohl(*(uint32_t *)&in->hdr[16]);
if (ahslen != 0) {
iscsi_set_error(iscsi, "cant handle expanded headers yet");
@@ -212,8 +211,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
switch (opcode) {
case ISCSI_PDU_LOGIN_RESPONSE:
if (iscsi_process_login_reply(iscsi, pdu, hdr, size)
!= 0) {
if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi login reply "
@@ -222,8 +220,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
break;
case ISCSI_PDU_TEXT_RESPONSE:
if (iscsi_process_text_reply(iscsi, pdu, hdr, size)
!= 0) {
if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi text reply "
@@ -232,8 +229,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
break;
case ISCSI_PDU_LOGOUT_RESPONSE:
if (iscsi_process_logout_reply(iscsi, pdu, hdr, size)
!= 0) {
if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi logout reply "
@@ -242,8 +238,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
break;
case ISCSI_PDU_SCSI_RESPONSE:
if (iscsi_process_scsi_reply(iscsi, pdu, hdr, size)
!= 0) {
if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi response reply "
@@ -252,7 +247,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
break;
case ISCSI_PDU_DATA_IN:
if (iscsi_process_scsi_data_in(iscsi, pdu, hdr, size,
if (iscsi_process_scsi_data_in(iscsi, pdu, in,
&is_finished) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
@@ -262,8 +257,7 @@ iscsi_process_pdu(struct iscsi_context *iscsi, const unsigned char *hdr,
}
break;
case ISCSI_PDU_NOP_IN:
if (iscsi_process_nop_out_reply(iscsi, pdu, hdr, size)
!= 0) {
if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
SLIST_REMOVE(&iscsi->waitpdu, pdu);
iscsi_free_pdu(iscsi, pdu);
iscsi_set_error(iscsi, "iscsi nop-in failed");

View File

@@ -196,18 +196,18 @@ iscsi_scsi_command_async(struct iscsi_context *iscsi, int lun,
int
iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr, int size)
struct iscsi_in_pdu *in)
{
int statsn, flags, response, status;
struct iscsi_scsi_cbdata *scsi_cbdata = pdu->scsi_cbdata;
struct scsi_task *task = scsi_cbdata->task;
statsn = ntohl(*(uint32_t *)&hdr[24]);
statsn = ntohl(*(uint32_t *)&in->hdr[24]);
if (statsn > (int)iscsi->statsn) {
iscsi->statsn = statsn;
}
flags = hdr[1];
flags = in->hdr[1];
if ((flags&ISCSI_PDU_DATA_FINAL) == 0) {
iscsi_set_error(iscsi, "scsi response pdu but Final bit is "
"not set: 0x%02x.", flags);
@@ -223,9 +223,9 @@ iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
return -1;
}
response = hdr[2];
response = in->hdr[2];
status = hdr[3];
status = in->hdr[3];
switch (status) {
case SCSI_STATUS_GOOD:
@@ -239,14 +239,13 @@ iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
pdu->private_data);
break;
case SCSI_STATUS_CHECK_CONDITION:
task->datain.size = size - ISCSI_HEADER_SIZE;
task->datain.size = in->data_pos;
task->datain.data = malloc(task->datain.size);
if (task->datain.data == NULL) {
iscsi_set_error(iscsi, "failed to allocate blob for "
"sense data");
}
memcpy(task->datain.data, hdr + ISCSI_HEADER_SIZE,
task->datain.size);
memcpy(task->datain.data, in->data, task->datain.size);
task->sense.error_type = task->datain.data[2] & 0x7f;
task->sense.key = task->datain.data[4] & 0x0f;
@@ -274,19 +273,19 @@ iscsi_process_scsi_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
int
iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
const unsigned char *hdr, int size _U_, int *is_finished)
struct iscsi_in_pdu *in, int *is_finished)
{
int statsn, flags, status;
struct iscsi_scsi_cbdata *scsi_cbdata = pdu->scsi_cbdata;
struct scsi_task *task = scsi_cbdata->task;
int dsl;
statsn = ntohl(*(uint32_t *)&hdr[24]);
statsn = ntohl(*(uint32_t *)&in->hdr[24]);
if (statsn > (int)iscsi->statsn) {
iscsi->statsn = statsn;
}
flags = hdr[1];
flags = in->hdr[1];
if ((flags&ISCSI_PDU_DATA_ACK_REQUESTED) != 0) {
iscsi_set_error(iscsi, "scsi response asked for ACK "
"0x%02x.", flags);
@@ -294,10 +293,10 @@ iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
pdu->private_data);
return -1;
}
dsl = ntohl(*(uint32_t *)&hdr[4])&0x00ffffff;
dsl = ntohl(*(uint32_t *)&in->hdr[4])&0x00ffffff;
if (iscsi_add_data(iscsi, &pdu->indata,
discard_const(hdr + ISCSI_HEADER_SIZE), dsl, 0)
in->data, dsl, 0)
!= 0) {
iscsi_set_error(iscsi, "Out-of-memory: failed to add data "
"to pdu in buffer.");
@@ -320,7 +319,7 @@ iscsi_process_scsi_data_in(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
/* this was the final data-in packet in the sequence and it has
* the s-bit set, so invoke the callback.
*/
status = hdr[3];
status = in->hdr[3];
task->datain.data = pdu->indata.data;
task->datain.size = pdu->indata.size;

View File

@@ -167,81 +167,85 @@ iscsi_which_events(struct iscsi_context *iscsi)
static int
iscsi_read_from_socket(struct iscsi_context *iscsi)
{
int available;
int size;
unsigned char *buf;
ssize_t count;
struct iscsi_in_pdu *in;
ssize_t data_size, count;
if (ioctl(iscsi->fd, FIONREAD, &available) != 0) {
iscsi_set_error(iscsi, "ioctl FIONREAD returned error : "
"%d", errno);
return -1;
}
if (available == 0) {
iscsi_set_error(iscsi, "no data readable in socket, "
"socket is closed");
return -1;
}
size = iscsi->insize - iscsi->inpos + available;
buf = malloc(size);
if (buf == NULL) {
iscsi_set_error(iscsi, "failed to allocate %d bytes for "
"input buffer", size);
return -1;
}
if (iscsi->insize > iscsi->inpos) {
memcpy(buf, iscsi->inbuf + iscsi->inpos,
iscsi->insize - iscsi->inpos);
iscsi->insize -= iscsi->inpos;
iscsi->inpos = 0;
}
count = read(iscsi->fd, buf + iscsi->insize, available);
if (count == -1) {
if (errno == EINTR) {
free(buf);
buf = NULL;
return 0;
if (iscsi->incoming == NULL) {
iscsi->incoming = malloc(sizeof(struct iscsi_in_pdu));
if (iscsi->incoming == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu");
return -1;
}
iscsi_set_error(iscsi, "read from socket failed, "
bzero(iscsi->incoming, sizeof(struct iscsi_in_pdu));
}
in = iscsi->incoming;
/* first we must read the header, including any digests */
if (in->hdr_pos < ISCSI_HEADER_SIZE) {
count = read(iscsi->fd, &in->hdr[in->hdr_pos], ISCSI_HEADER_SIZE - in->hdr_pos);
if (count < 0) {
if (errno == EINTR) {
return 0;
}
iscsi_set_error(iscsi, "read from socket failed, "
"errno:%d", errno);
free(buf);
buf = NULL;
return -1;
}
free(iscsi->inbuf);
iscsi->inbuf = buf;
iscsi->insize += count;
while (1) {
if (iscsi->insize - iscsi->inpos < ISCSI_RAW_HEADER_SIZE) {
return 0;
}
count = iscsi_get_pdu_size(iscsi,
iscsi->inbuf + iscsi->inpos);
if (iscsi->insize + iscsi->inpos < count) {
return 0;
}
if (iscsi_process_pdu(iscsi, iscsi->inbuf + iscsi->inpos,
count) != 0) {
iscsi->inpos += count;
return -1;
}
iscsi->inpos += count;
if (iscsi->inpos == iscsi->insize) {
free(iscsi->inbuf);
iscsi->inbuf = NULL;
iscsi->insize = 0;
iscsi->inpos = 0;
if (count == 0) {
return 0;
}
if (iscsi->inpos > iscsi->insize) {
iscsi_set_error(iscsi, "inpos > insize. bug!");
in->hdr_pos += count;
}
if (in->hdr_pos < ISCSI_HEADER_SIZE) {
/* we dont have the full header yet, so return */
return 0;
}
data_size = iscsi_get_pdu_data_size(&in->hdr[0]);
if (data_size != 0) {
if (in->data == NULL) {
in->data = malloc(data_size);
if (in->data == NULL) {
iscsi_set_error(iscsi, "Out-of-memory: failed to malloc iscsi_in_pdu->data(%d)", (int)data_size);
return -1;
}
}
count = read(iscsi->fd, &in->data[in->data_pos], data_size - in->data_pos);
if (count < 0) {
if (errno == EINTR) {
return 0;
}
iscsi_set_error(iscsi, "read from socket failed, "
"errno:%d", errno);
return -1;
}
if (count == 0) {
return 0;
}
in->data_pos += count;
}
if (in->data_pos < data_size) {
return 0;
}
SLIST_ADD_END(&iscsi->inqueue, in);
iscsi->incoming = NULL;
while (iscsi->inqueue != NULL) {
struct iscsi_in_pdu *in = iscsi->inqueue;
if (iscsi_process_pdu(iscsi, in) != 0) {
return -1;
}
SLIST_REMOVE(&iscsi->inqueue, in);
iscsi_free_iscsi_in_pdu(in);
}
return 0;
}
@@ -353,3 +357,19 @@ iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
return 0;
}
void
iscsi_free_iscsi_in_pdu(struct iscsi_in_pdu *in)
{
free(in->data);
free(in);
}
void
iscsi_free_iscsi_inqueue(struct iscsi_in_pdu *inqueue)
{
while (inqueue != NULL) {
struct iscsi_in_pdu *next = inqueue->next;
iscsi_free_iscsi_in_pdu(inqueue);
inqueue = next;
}
}