]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[iscsi] Send any padding inline with the data segment
authorMichael Brown <mcb30@ipxe.org>
Thu, 1 Mar 2012 16:26:38 +0000 (16:26 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 1 Mar 2012 16:33:05 +0000 (16:33 +0000)
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>
src/include/ipxe/iscsi.h
src/net/tcp/iscsi.c

index 5d3d73b0ceb3cc93318dea07fb3a9c700d04fd1f..b4de793a47d112acb3bc063588a182b3a64f117a 100644 (file)
@@ -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 */
index fa1bb398096a302cd8d5d3e6068c07058d76801c..9eaf3cc50633edcdfe7b3370d979a5ce8966fd44 100644 (file)
@@ -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: