#ifndef _GPXE_XFER_H #define _GPXE_XFER_H /** @file * * Data transfer interfaces * */ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include #include 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 /* _GPXE_XFER_H */