mirror of https://github.com/ipxe/ipxe.git
[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>pull/6/head
parent
cb10137e19
commit
1d293776ea
|
@ -515,8 +515,6 @@ enum iscsi_tx_state {
|
||||||
ISCSI_TX_AHS,
|
ISCSI_TX_AHS,
|
||||||
/** Sending the data segment */
|
/** Sending the data segment */
|
||||||
ISCSI_TX_DATA,
|
ISCSI_TX_DATA,
|
||||||
/** Sending the data segment padding */
|
|
||||||
ISCSI_TX_DATA_PADDING,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** State of an iSCSI RX engine */
|
/** State of an iSCSI RX engine */
|
||||||
|
|
|
@ -570,20 +570,23 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) {
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *iobuf;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t pad_len;
|
||||||
|
|
||||||
offset = ntohl ( data_out->offset );
|
offset = ntohl ( data_out->offset );
|
||||||
len = ISCSI_DATA_LEN ( data_out->lengths );
|
len = ISCSI_DATA_LEN ( data_out->lengths );
|
||||||
|
pad_len = ISCSI_DATA_PAD_LEN ( data_out->lengths );
|
||||||
|
|
||||||
assert ( iscsi->command != NULL );
|
assert ( iscsi->command != NULL );
|
||||||
assert ( iscsi->command->data_out );
|
assert ( iscsi->command->data_out );
|
||||||
assert ( ( offset + len ) <= iscsi->command->data_out_len );
|
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 )
|
if ( ! iobuf )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
copy_from_user ( iob_put ( iobuf, len ),
|
copy_from_user ( iob_put ( iobuf, len ),
|
||||||
iscsi->command->data_out, offset, len );
|
iscsi->command->data_out, offset, len );
|
||||||
|
memset ( iob_put ( iobuf, pad_len ), 0, pad_len );
|
||||||
|
|
||||||
return xfer_deliver_iob ( &iscsi->socket, iobuf );
|
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 iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request;
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *iobuf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t pad_len;
|
||||||
|
|
||||||
len = ISCSI_DATA_LEN ( request->lengths );
|
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 )
|
if ( ! iobuf )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
iob_put ( iobuf, len );
|
iob_put ( iobuf, len );
|
||||||
iscsi_build_login_request_strings ( iscsi, iobuf->data, 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 );
|
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
|
* Complete iSCSI PDU transmission
|
||||||
*
|
*
|
||||||
|
@ -1494,11 +1480,6 @@ static void iscsi_tx_step ( struct iscsi_session *iscsi ) {
|
||||||
case ISCSI_TX_DATA:
|
case ISCSI_TX_DATA:
|
||||||
tx = iscsi_tx_data;
|
tx = iscsi_tx_data;
|
||||||
tx_len = ISCSI_DATA_LEN ( common->lengths );
|
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;
|
next_state = ISCSI_TX_IDLE;
|
||||||
break;
|
break;
|
||||||
case ISCSI_TX_IDLE:
|
case ISCSI_TX_IDLE:
|
||||||
|
|
Loading…
Reference in New Issue