From 1d293776ea290ae1f4d1228f3278030facf97a4b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Mar 2012 16:26:38 +0000 Subject: [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 Signed-off-by: Michael Brown --- src/include/ipxe/iscsi.h | 2 -- 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 ); } @@ -1415,27 +1422,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 * @@ -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: -- cgit v1.2.3-55-g7522