[interface] Convert all data-xfer interfaces to generic interfaces

Remove data-xfer as an interface type, and replace data-xfer
interfaces with generic interfaces supporting the data-xfer methods.

Filter interfaces (as used by the TLS layer) are handled using the
generic pass-through interface capability.  A side-effect of this is
that deliver_raw() no longer exists as a data-xfer method.  (In
practice this doesn't lose any efficiency, since there are no
instances within the current codebase where xfer_deliver_raw() is used
to pass data to an interface supporting the deliver_raw() method.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2010-06-16 01:31:29 +01:00
parent 7b4fbd93a5
commit 4327d5d39f
31 changed files with 764 additions and 1511 deletions

View File

@@ -35,9 +35,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/sha1.h>
#include <ipxe/aes.h>
#include <ipxe/rsa.h>
#include <ipxe/iobuf.h>
#include <ipxe/xfer.h>
#include <ipxe/open.h>
#include <ipxe/filter.h>
#include <ipxe/asn1.h>
#include <ipxe/x509.h>
#include <ipxe/tls.h>
@@ -107,10 +107,8 @@ static void tls_close ( struct tls_session *tls, int rc ) {
process_del ( &tls->process );
/* Close ciphertext and plaintext streams */
xfer_nullify ( &tls->cipherstream.xfer );
xfer_close ( &tls->cipherstream.xfer, rc );
xfer_nullify ( &tls->plainstream.xfer );
xfer_close ( &tls->plainstream.xfer, rc );
intf_shutdown ( &tls->cipherstream, rc );
intf_shutdown ( &tls->plainstream, rc );
}
/******************************************************************************
@@ -1030,7 +1028,7 @@ static int tls_new_record ( struct tls_session *tls,
case TLS_TYPE_HANDSHAKE:
return tls_new_handshake ( tls, data, len );
case TLS_TYPE_DATA:
return xfer_deliver_raw ( &tls->plainstream.xfer, data, len );
return xfer_deliver_raw ( &tls->plainstream, data, len );
default:
/* RFC4346 says that we should just ignore unknown
* record types.
@@ -1209,8 +1207,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
/* Allocate ciphertext */
ciphertext_len = ( sizeof ( *tlshdr ) + plaintext_len );
ciphertext = xfer_alloc_iob ( &tls->cipherstream.xfer,
ciphertext_len );
ciphertext = xfer_alloc_iob ( &tls->cipherstream, ciphertext_len );
if ( ! ciphertext ) {
DBGC ( tls, "TLS %p could not allocate %zd bytes for "
"ciphertext\n", tls, ciphertext_len );
@@ -1234,9 +1231,8 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type,
plaintext = NULL;
/* Send ciphertext */
rc = xfer_deliver_iob ( &tls->cipherstream.xfer, ciphertext );
ciphertext = NULL;
if ( rc != 0 ) {
if ( ( rc = xfer_deliver_iob ( &tls->cipherstream,
iob_disown ( ciphertext ) ) ) != 0 ) {
DBGC ( tls, "TLS %p could not deliver ciphertext: %s\n",
tls, strerror ( rc ) );
goto done;
@@ -1435,66 +1431,61 @@ static int tls_new_ciphertext ( struct tls_session *tls,
******************************************************************************
*/
/**
* Close interface
*
* @v xfer Plainstream data transfer interface
* @v rc Reason for close
*/
static void tls_plainstream_close ( struct xfer_interface *xfer, int rc ) {
struct tls_session *tls =
container_of ( xfer, struct tls_session, plainstream.xfer );
tls_close ( tls, rc );
}
/**
* Check flow control window
*
* @v xfer Plainstream data transfer interface
* @v tls TLS session
* @ret len Length of window
*/
static size_t tls_plainstream_window ( struct xfer_interface *xfer ) {
struct tls_session *tls =
container_of ( xfer, struct tls_session, plainstream.xfer );
static size_t tls_plainstream_window ( struct tls_session *tls ) {
/* Block window unless we are ready to accept data */
if ( tls->tx_state != TLS_TX_DATA )
return 0;
return filter_window ( xfer );
return xfer_window ( &tls->cipherstream );
}
/**
* Deliver datagram as raw data
*
* @v xfer Plainstream data transfer interface
* @v data Data buffer
* @v len Length of data buffer
* @v tls TLS session
* @v iobuf I/O buffer
* @v meta Data transfer metadata
* @ret rc Return status code
*/
static int tls_plainstream_deliver_raw ( struct xfer_interface *xfer,
const void *data, size_t len ) {
struct tls_session *tls =
container_of ( xfer, struct tls_session, plainstream.xfer );
static int tls_plainstream_deliver ( struct tls_session *tls,
struct io_buffer *iobuf,
struct xfer_metadata *meta __unused ) {
int rc;
/* Refuse unless we are ready to accept data */
if ( tls->tx_state != TLS_TX_DATA )
return -ENOTCONN;
if ( tls->tx_state != TLS_TX_DATA ) {
rc = -ENOTCONN;
goto done;
}
return tls_send_plaintext ( tls, TLS_TYPE_DATA, data, len );
if ( ( rc = tls_send_plaintext ( tls, TLS_TYPE_DATA, iobuf->data,
iob_len ( iobuf ) ) ) != 0 )
goto done;
done:
free_iob ( iobuf );
return rc;
}
/** TLS plaintext stream operations */
static struct xfer_interface_operations tls_plainstream_operations = {
.close = tls_plainstream_close,
.vredirect = ignore_xfer_vredirect,
.window = tls_plainstream_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = tls_plainstream_deliver_raw,
/** TLS plaintext stream interface operations */
static struct interface_operation tls_plainstream_ops[] = {
INTF_OP ( xfer_deliver, struct tls_session *, tls_plainstream_deliver ),
INTF_OP ( xfer_window, struct tls_session *, tls_plainstream_window ),
INTF_OP ( intf_close, struct tls_session *, tls_close ),
};
/** TLS plaintext stream interface descriptor */
static struct interface_descriptor tls_plainstream_desc =
INTF_DESC_PASSTHRU ( struct tls_session, plainstream,
tls_plainstream_ops, cipherstream );
/******************************************************************************
*
* Ciphertext stream operations
@@ -1502,19 +1493,6 @@ static struct xfer_interface_operations tls_plainstream_operations = {
******************************************************************************
*/
/**
* Close interface
*
* @v xfer Plainstream data transfer interface
* @v rc Reason for close
*/
static void tls_cipherstream_close ( struct xfer_interface *xfer, int rc ) {
struct tls_session *tls =
container_of ( xfer, struct tls_session, cipherstream.xfer );
tls_close ( tls, rc );
}
/**
* Handle received TLS header
*
@@ -1569,22 +1547,21 @@ static int tls_newdata_process_data ( struct tls_session *tls ) {
/**
* Receive new ciphertext
*
* @v app Stream application
* @v data Data received
* @v len Length of received data
* @v tls TLS session
* @v iobuf I/O buffer
* @v meta Data transfer metadat
* @ret rc Return status code
*/
static int tls_cipherstream_deliver_raw ( struct xfer_interface *xfer,
const void *data, size_t len ) {
struct tls_session *tls =
container_of ( xfer, struct tls_session, cipherstream.xfer );
static int tls_cipherstream_deliver ( struct tls_session *tls,
struct io_buffer *iobuf,
struct xfer_metadata *xfer __unused ) {
size_t frag_len;
void *buf;
size_t buf_len;
int ( * process ) ( struct tls_session *tls );
int rc;
while ( len ) {
while ( iob_len ( iobuf ) ) {
/* Select buffer according to current state */
switch ( tls->rx_state ) {
case TLS_RX_HEADER:
@@ -1599,41 +1576,46 @@ static int tls_cipherstream_deliver_raw ( struct xfer_interface *xfer,
break;
default:
assert ( 0 );
return -EINVAL;
rc = -EINVAL;
goto done;
}
/* Copy data portion to buffer */
frag_len = ( buf_len - tls->rx_rcvd );
if ( frag_len > len )
frag_len = len;
memcpy ( ( buf + tls->rx_rcvd ), data, frag_len );
if ( frag_len > iob_len ( iobuf ) )
frag_len = iob_len ( iobuf );
memcpy ( ( buf + tls->rx_rcvd ), iobuf->data, frag_len );
tls->rx_rcvd += frag_len;
data += frag_len;
len -= frag_len;
iob_pull ( iobuf, frag_len );
/* Process data if buffer is now full */
if ( tls->rx_rcvd == buf_len ) {
if ( ( rc = process ( tls ) ) != 0 ) {
tls_close ( tls, rc );
return rc;
goto done;
}
tls->rx_rcvd = 0;
}
}
rc = 0;
return 0;
done:
free_iob ( iobuf );
return rc;
}
/** TLS ciphertext stream operations */
static struct xfer_interface_operations tls_cipherstream_operations = {
.close = tls_cipherstream_close,
.vredirect = xfer_vreopen,
.window = filter_window,
.alloc_iob = default_xfer_alloc_iob,
.deliver_iob = xfer_deliver_as_raw,
.deliver_raw = tls_cipherstream_deliver_raw,
/** TLS ciphertext stream interface operations */
static struct interface_operation tls_cipherstream_ops[] = {
INTF_OP ( xfer_deliver, struct tls_session *,
tls_cipherstream_deliver ),
INTF_OP ( intf_close, struct tls_session *, tls_close ),
};
/** TLS ciphertext stream interface descriptor */
static struct interface_descriptor tls_cipherstream_desc =
INTF_DESC_PASSTHRU ( struct tls_session, cipherstream,
tls_cipherstream_ops, plainstream );
/******************************************************************************
*
* Controlling process
@@ -1652,7 +1634,7 @@ static void tls_step ( struct process *process ) {
int rc;
/* Wait for cipherstream to become ready */
if ( ! xfer_window ( &tls->cipherstream.xfer ) )
if ( ! xfer_window ( &tls->cipherstream ) )
return;
switch ( tls->tx_state ) {
@@ -1723,7 +1705,7 @@ static void tls_step ( struct process *process ) {
******************************************************************************
*/
int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
int add_tls ( struct interface *xfer, struct interface **next ) {
struct tls_session *tls;
/* Allocate and initialise TLS structure */
@@ -1732,9 +1714,8 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
return -ENOMEM;
memset ( tls, 0, sizeof ( *tls ) );
ref_init ( &tls->refcnt, free_tls );
filter_init ( &tls->plainstream, &tls_plainstream_operations,
&tls->cipherstream, &tls_cipherstream_operations,
&tls->refcnt );
intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt );
intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt );
tls_clear_cipher ( tls, &tls->tx_cipherspec );
tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
tls_clear_cipher ( tls, &tls->rx_cipherspec );
@@ -1751,9 +1732,8 @@ int add_tls ( struct xfer_interface *xfer, struct xfer_interface **next ) {
process_init ( &tls->process, tls_step, &tls->refcnt );
/* Attach to parent interface, mortalise self, and return */
xfer_plug_plug ( &tls->plainstream.xfer, xfer );
*next = &tls->cipherstream.xfer;
intf_plug_plug ( &tls->plainstream, xfer );
*next = &tls->cipherstream;
ref_put ( &tls->refcnt );
return 0;
}