diff --git a/include/iscsi-private.h b/include/iscsi-private.h index 45716c7..406c7ea 100644 --- a/include/iscsi-private.h +++ b/include/iscsi-private.h @@ -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, ...); diff --git a/lib/discovery.c b/lib/discovery.c index bfa1d99..765659a 100644 --- a/lib/discovery.c +++ b/lib/discovery.c @@ -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; } diff --git a/lib/init.c b/lib/init.c index 9ddd201..242f786 100644 --- a/lib/init.c +++ b/lib/init.c @@ -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; } + + diff --git a/lib/login.c b/lib/login.c index fe497e5..3205094 100644 --- a/lib/login.c +++ b/lib/login.c @@ -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); diff --git a/lib/nop.c b/lib/nop.c index 2cb6749..152ef53 100644 --- a/lib/nop.c +++ b/lib/nop.c @@ -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); diff --git a/lib/pdu.c b/lib/pdu.c index 25dc76d..07d058b 100644 --- a/lib/pdu.c +++ b/lib/pdu.c @@ -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"); diff --git a/lib/scsi-command.c b/lib/scsi-command.c index ff5341b..62f5838 100644 --- a/lib/scsi-command.c +++ b/lib/scsi-command.c @@ -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; diff --git a/lib/socket.c b/lib/socket.c index c52be6a..b859fb3 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -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; + } +}