summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2012-03-01 17:26:38 +0100
committerMichael Brown2012-03-01 17:33:05 +0100
commit1d293776ea290ae1f4d1228f3278030facf97a4b (patch)
treec58bcf0708a3c8074cca8f77fb4b6c310b883178
parent[http] Recognise status code 303 as valid (diff)
downloadipxe-1d293776ea290ae1f4d1228f3278030facf97a4b.tar.gz
ipxe-1d293776ea290ae1f4d1228f3278030facf97a4b.tar.xz
ipxe-1d293776ea290ae1f4d1228f3278030facf97a4b.zip
[iscsi] Send any padding inline with the data segment
Some iSCSI targets respond to a PDU before receiving the padding bytes. If the target responds quickly enough, this can cause iPXE to start processing a new TX PDU before the padding bytes have been sent, which results in a protocol violation. Fix by always transmitting the padding bytes along with the data segment. Originally-fixed-by: Shyam Iyer <shyam_iyer@dell.com> Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/include/ipxe/iscsi.h2
-rw-r--r--src/net/tcp/iscsi.c37
2 files changed, 9 insertions, 30 deletions
diff --git a/src/include/ipxe/iscsi.h b/src/include/ipxe/iscsi.h
index 5d3d73b0..b4de793a 100644
--- a/src/include/ipxe/iscsi.h
+++ b/src/include/ipxe/iscsi.h
@@ -515,8 +515,6 @@ enum iscsi_tx_state {
ISCSI_TX_AHS,
/** Sending the data segment */
ISCSI_TX_DATA,
- /** Sending the data segment padding */
- ISCSI_TX_DATA_PADDING,
};
/** State of an iSCSI RX engine */
diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c
index fa1bb398..9eaf3cc5 100644
--- a/src/net/tcp/iscsi.c
+++ b/src/net/tcp/iscsi.c
@@ -570,20 +570,23 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
struct io_buffer *iobuf;
unsigned long offset;
size_t len;
+ size_t pad_len;
offset = ntohl ( data_out->offset );
len = ISCSI_DATA_LEN ( data_out->lengths );
+ pad_len = ISCSI_DATA_PAD_LEN ( data_out->lengths );
assert ( iscsi->command != NULL );
assert ( iscsi->command->data_out );
assert ( ( offset + len ) <= iscsi->command->data_out_len );
- iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+ iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) );
if ( ! iobuf )
return -ENOMEM;
copy_from_user ( iob_put ( iobuf, len ),
iscsi->command->data_out, offset, len );
+ memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
return xfer_deliver_iob ( &iscsi->socket, iobuf );
}
@@ -801,13 +804,17 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) {
struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
struct io_buffer *iobuf;
size_t len;
+ size_t pad_len;
len = ISCSI_DATA_LEN ( request->lengths );
- iobuf = xfer_alloc_iob ( &iscsi->socket, len );
+ pad_len = ISCSI_DATA_PAD_LEN ( request->lengths );
+ iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) );
if ( ! iobuf )
return -ENOMEM;
iob_put ( iobuf, len );
iscsi_build_login_request_strings ( iscsi, iobuf->data, len );
+ memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
+
return xfer_deliver_iob ( &iscsi->socket, iobuf );
}
@@ -1416,27 +1423,6 @@ static int iscsi_tx_data ( struct iscsi_session *iscsi ) {
}
/**
- * Transmit data padding of an iSCSI PDU
- *
- * @v iscsi iSCSI session
- * @ret rc Return status code
- *
- * Handle transmission of any data padding in a PDU data segment.
- * iscsi::tx_bhs will be valid when this is called.
- */
-static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) {
- static const char pad[] = { '\0', '\0', '\0' };
- struct iscsi_bhs_common *common = &iscsi->tx_bhs.common;
- size_t pad_len;
-
- pad_len = ISCSI_DATA_PAD_LEN ( common->lengths );
- if ( ! pad_len )
- return 0;
-
- return xfer_deliver_raw ( &iscsi->socket, pad, pad_len );
-}
-
-/**
* Complete iSCSI PDU transmission
*
* @v iscsi iSCSI session
@@ -1494,11 +1480,6 @@ static void iscsi_tx_step ( struct iscsi_session *iscsi ) {
case ISCSI_TX_DATA:
tx = iscsi_tx_data;
tx_len = ISCSI_DATA_LEN ( common->lengths );
- next_state = ISCSI_TX_DATA_PADDING;
- break;
- case ISCSI_TX_DATA_PADDING:
- tx = iscsi_tx_data_padding;
- tx_len = ISCSI_DATA_PAD_LEN ( common->lengths );
next_state = ISCSI_TX_IDLE;
break;
case ISCSI_TX_IDLE: