diff options
author | Michael Brown | 2012-03-01 17:26:38 +0100 |
---|---|---|
committer | Michael Brown | 2012-03-01 17:33:05 +0100 |
commit | 1d293776ea290ae1f4d1228f3278030facf97a4b (patch) | |
tree | c58bcf0708a3c8074cca8f77fb4b6c310b883178 | |
parent | [http] Recognise status code 303 as valid (diff) | |
download | ipxe-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.h | 2 | ||||
-rw-r--r-- | src/net/tcp/iscsi.c | 37 |
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: |