diff options
Diffstat (limited to 'src/include/ipxe/xfer.h')
-rw-r--r-- | src/include/ipxe/xfer.h | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/include/ipxe/xfer.h b/src/include/ipxe/xfer.h new file mode 100644 index 000000000..ad41e932c --- /dev/null +++ b/src/include/ipxe/xfer.h @@ -0,0 +1,277 @@ +#ifndef _IPXE_XFER_H +#define _IPXE_XFER_H + +/** @file + * + * Data transfer interfaces + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <stddef.h> +#include <stdarg.h> +#include <ipxe/interface.h> +#include <ipxe/iobuf.h> + +struct xfer_interface; +struct xfer_metadata; + +/** Data transfer interface operations */ +struct xfer_interface_operations { + /** Close interface + * + * @v xfer Data transfer interface + * @v rc Reason for close + */ + void ( * close ) ( struct xfer_interface *xfer, int rc ); + /** Redirect to new location + * + * @v xfer Data transfer interface + * @v type New location type + * @v args Remaining arguments depend upon location type + * @ret rc Return status code + */ + int ( * vredirect ) ( struct xfer_interface *xfer, int type, + va_list args ); + /** Check flow control window + * + * @v xfer Data transfer interface + * @ret len Length of window + * + * Flow control is regarded as advisory but not mandatory. + * Users who have control over their own rate of data + * generation should perform a flow control check before + * generating new data. Users who have no control (such as + * NIC drivers or filter layers) are not obliged to check. + * + * Data transfer interfaces must be prepared to accept + * datagrams even if they are advertising a window of zero + * bytes. + */ + size_t ( * window ) ( struct xfer_interface *xfer ); + /** Allocate I/O buffer + * + * @v xfer Data transfer interface + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ + struct io_buffer * ( * alloc_iob ) ( struct xfer_interface *xfer, + size_t len ); + /** Deliver datagram as I/O buffer with metadata + * + * @v xfer Data transfer interface + * @v iobuf Datagram I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + * + * A data transfer interface that wishes to support only raw + * data delivery should set this method to + * xfer_deliver_as_raw(). + */ + int ( * deliver_iob ) ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta ); + /** Deliver datagram as raw data + * + * @v xfer Data transfer interface + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + * + * A data transfer interface that wishes to support only I/O + * buffer delivery should set this method to + * xfer_deliver_as_iob(). + */ + int ( * deliver_raw ) ( struct xfer_interface *xfer, + const void *data, size_t len ); +}; + +/** A data transfer interface */ +struct xfer_interface { + /** Generic object communication interface */ + struct interface intf; + /** Operations for received messages */ + struct xfer_interface_operations *op; +}; + +/** Basis positions for seek() events */ +enum seek_whence { + SEEK_CUR = 0, + SEEK_SET, +}; + +/** Data transfer metadata */ +struct xfer_metadata { + /** Position of data within stream */ + off_t offset; + /** Basis for data position + * + * Must be one of @c SEEK_CUR or @c SEEK_SET. + */ + int whence; + /** Source socket address, or NULL */ + struct sockaddr *src; + /** Destination socket address, or NULL */ + struct sockaddr *dest; + /** Network device, or NULL */ + struct net_device *netdev; +}; + +/** + * Describe seek basis + * + * @v whence Basis for new position + */ +static inline __attribute__ (( always_inline )) const char * +whence_text ( int whence ) { + switch ( whence ) { + case SEEK_CUR: return "CUR"; + case SEEK_SET: return "SET"; + default: return "INVALID"; + } +} + +extern struct xfer_interface null_xfer; +extern struct xfer_interface_operations null_xfer_ops; + +extern void xfer_close ( struct xfer_interface *xfer, int rc ); +extern int xfer_vredirect ( struct xfer_interface *xfer, int type, + va_list args ); +extern int xfer_redirect ( struct xfer_interface *xfer, int type, ... ); +extern size_t xfer_window ( struct xfer_interface *xfer ); +extern struct io_buffer * xfer_alloc_iob ( struct xfer_interface *xfer, + size_t len ); +extern int xfer_deliver_iob ( struct xfer_interface *xfer, + struct io_buffer *iobuf ); +extern int xfer_deliver_iob_meta ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta ); +extern int xfer_deliver_raw ( struct xfer_interface *xfer, + const void *data, size_t len ); +extern int xfer_vprintf ( struct xfer_interface *xfer, + const char *format, va_list args ); +extern int __attribute__ (( format ( printf, 2, 3 ) )) +xfer_printf ( struct xfer_interface *xfer, const char *format, ... ); +extern int xfer_seek ( struct xfer_interface *xfer, off_t offset, int whence ); + +extern void ignore_xfer_close ( struct xfer_interface *xfer, int rc ); +extern int ignore_xfer_vredirect ( struct xfer_interface *xfer, + int type, va_list args ); +extern size_t unlimited_xfer_window ( struct xfer_interface *xfer ); +extern size_t no_xfer_window ( struct xfer_interface *xfer ); +extern struct io_buffer * default_xfer_alloc_iob ( struct xfer_interface *xfer, + size_t len ); +extern int xfer_deliver_as_raw ( struct xfer_interface *xfer, + struct io_buffer *iobuf, + struct xfer_metadata *meta ); +extern int xfer_deliver_as_iob ( struct xfer_interface *xfer, + const void *data, size_t len ); +extern int ignore_xfer_deliver_raw ( struct xfer_interface *xfer, + const void *data __unused, size_t len ); + +/** + * Initialise a data transfer interface + * + * @v xfer Data transfer interface + * @v op Data transfer interface operations + * @v refcnt Containing object reference counter, or NULL + */ +static inline void xfer_init ( struct xfer_interface *xfer, + struct xfer_interface_operations *op, + struct refcnt *refcnt ) { + xfer->intf.dest = &null_xfer.intf; + xfer->intf.refcnt = refcnt; + xfer->op = op; +} + +/** + * Initialise a static data transfer interface + * + * @v operations Data transfer interface operations + */ +#define XFER_INIT( operations ) { \ + .intf = { \ + .dest = &null_xfer.intf, \ + .refcnt = NULL, \ + }, \ + .op = operations, \ + } + +/** + * Get data transfer interface from generic object communication interface + * + * @v intf Generic object communication interface + * @ret xfer Data transfer interface + */ +static inline __attribute__ (( always_inline )) struct xfer_interface * +intf_to_xfer ( struct interface *intf ) { + return container_of ( intf, struct xfer_interface, intf ); +} + +/** + * Get reference to destination data transfer interface + * + * @v xfer Data transfer interface + * @ret dest Destination interface + */ +static inline __attribute__ (( always_inline )) struct xfer_interface * +xfer_get_dest ( struct xfer_interface *xfer ) { + return intf_to_xfer ( intf_get ( xfer->intf.dest ) ); +} + +/** + * Drop reference to data transfer interface + * + * @v xfer Data transfer interface + */ +static inline __attribute__ (( always_inline )) void +xfer_put ( struct xfer_interface *xfer ) { + intf_put ( &xfer->intf ); +} + +/** + * Plug a data transfer interface into a new destination interface + * + * @v xfer Data transfer interface + * @v dest New destination interface + */ +static inline __attribute__ (( always_inline )) void +xfer_plug ( struct xfer_interface *xfer, struct xfer_interface *dest ) { + plug ( &xfer->intf, &dest->intf ); +} + +/** + * Plug two data transfer interfaces together + * + * @v a Data transfer interface A + * @v b Data transfer interface B + */ +static inline __attribute__ (( always_inline )) void +xfer_plug_plug ( struct xfer_interface *a, struct xfer_interface *b ) { + plug_plug ( &a->intf, &b->intf ); +} + +/** + * Unplug a data transfer interface + * + * @v xfer Data transfer interface + */ +static inline __attribute__ (( always_inline )) void +xfer_unplug ( struct xfer_interface *xfer ) { + plug ( &xfer->intf, &null_xfer.intf ); +} + +/** + * Stop using a data transfer interface + * + * @v xfer Data transfer interface + * + * After calling this method, no further messages will be received via + * the interface. + */ +static inline void xfer_nullify ( struct xfer_interface *xfer ) { + xfer->op = &null_xfer_ops; +}; + +#endif /* _IPXE_XFER_H */ |