2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
30 #include <ipxe/iobuf.h>
31 #include <ipxe/xfer.h>
32 #include <ipxe/open.h>
36 * Data transfer interfaces
41 * Dummy transfer metadata
43 * This gets passed to xfer_interface::deliver() and equivalents when
44 * no metadata is available.
46 static struct xfer_metadata dummy_metadata;
48 /*****************************************************************************
50 * Data transfer interface operations
55 * Send redirection event
57 * @v intf Data transfer interface
58 * @v type New location type
59 * @v args Remaining arguments depend upon location type
60 * @ret rc Return status code
62 int xfer_vredirect ( struct interface *intf, int type, va_list args ) {
63 struct interface tmp = INTF_INIT ( null_intf_desc );
64 struct interface *dest;
65 xfer_vredirect_TYPE ( void * ) *op =
66 intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest );
67 void *object = intf_object ( dest );
70 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect\n",
71 INTF_INTF_DBG ( intf, dest ) );
74 rc = op ( object, type, args );
76 /* Default is to reopen the interface as instructed,
77 * then send xfer_window_changed() messages to both
78 * new child and parent interfaces. Since our
79 * original child interface is likely to be closed and
80 * unplugged as a result of the call to
81 * xfer_vreopen(), we create a temporary interface in
82 * order to be able to send xfer_window_changed() to
85 intf_plug ( &tmp, dest );
86 rc = xfer_vreopen ( dest, type, args );
88 xfer_window_changed ( dest );
89 xfer_window_changed ( &tmp );
95 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect "
96 "failed: %s\n", INTF_INTF_DBG ( intf, dest ),
105 * Check flow control window
107 * @v intf Data transfer interface
108 * @ret len Length of window
110 size_t xfer_window ( struct interface *intf ) {
111 struct interface *dest;
112 xfer_window_TYPE ( void * ) *op =
113 intf_get_dest_op ( intf, xfer_window, &dest );
114 void *object = intf_object ( dest );
120 /* Default is to provide an unlimited window */
121 len = ~( ( size_t ) 0 );
129 * Report change of flow control window
131 * @v intf Data transfer interface
133 * Note that this method is used to indicate only unsolicited changes
134 * in the flow control window. In particular, this method must not be
135 * called as part of the response to xfer_deliver(), since that could
136 * easily lead to an infinite loop. Callers of xfer_deliver() should
137 * assume that the flow control window will have changed without
138 * generating an xfer_window_changed() message.
140 void xfer_window_changed ( struct interface *intf ) {
142 intf_poke ( intf, xfer_window_changed );
146 * Allocate I/O buffer
148 * @v intf Data transfer interface
149 * @v len I/O buffer payload length
150 * @ret iobuf I/O buffer
152 struct io_buffer * xfer_alloc_iob ( struct interface *intf, size_t len ) {
153 struct interface *dest;
154 xfer_alloc_iob_TYPE ( void * ) *op =
155 intf_get_dest_op ( intf, xfer_alloc_iob, &dest );
156 void *object = intf_object ( dest );
157 struct io_buffer *iobuf;
159 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob %zd\n",
160 INTF_INTF_DBG ( intf, dest ), len );
163 iobuf = op ( object, len );
165 /* Default is to allocate an I/O buffer with no
168 iobuf = alloc_iob ( len );
172 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob "
173 "failed\n", INTF_INTF_DBG ( intf, dest ) );
183 * @v intf Data transfer interface
184 * @v iobuf Datagram I/O buffer
185 * @v meta Data transfer metadata
186 * @ret rc Return status code
188 int xfer_deliver ( struct interface *intf,
189 struct io_buffer *iobuf,
190 struct xfer_metadata *meta ) {
191 struct interface *dest;
192 xfer_deliver_TYPE ( void * ) *op =
193 intf_get_dest_op ( intf, xfer_deliver, &dest );
194 void *object = intf_object ( dest );
197 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n",
198 INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) );
201 rc = op ( object, iobuf, meta );
203 /* Default is to discard the I/O buffer */
209 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT
210 " deliver failed: %s\n",
211 INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
218 /*****************************************************************************
220 * Data transfer interface helper functions
225 * Send redirection event
227 * @v intf Data transfer interface
228 * @v type New location type
229 * @v ... Remaining arguments depend upon location type
230 * @ret rc Return status code
232 int xfer_redirect ( struct interface *intf, int type, ... ) {
236 va_start ( args, type );
237 rc = xfer_vredirect ( intf, type, args );
243 * Deliver datagram as I/O buffer without metadata
245 * @v intf Data transfer interface
246 * @v iobuf Datagram I/O buffer
247 * @ret rc Return status code
249 int xfer_deliver_iob ( struct interface *intf, struct io_buffer *iobuf ) {
250 return xfer_deliver ( intf, iobuf, &dummy_metadata );
254 * Deliver datagram as raw data
256 * @v intf Data transfer interface
258 * @v len Length of data
259 * @v meta Data transfer metadata
260 * @ret rc Return status code
262 int xfer_deliver_raw_meta ( struct interface *intf, const void *data,
263 size_t len, struct xfer_metadata *meta ) {
264 struct io_buffer *iobuf;
266 iobuf = xfer_alloc_iob ( intf, len );
270 memcpy ( iob_put ( iobuf, len ), data, len );
271 return xfer_deliver ( intf, iobuf, meta );
275 * Deliver datagram as raw data without metadata
277 * @v intf Data transfer interface
279 * @v len Length of data
280 * @ret rc Return status code
282 int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) {
283 return xfer_deliver_raw_meta ( intf, data, len, &dummy_metadata );
287 * Deliver formatted string
289 * @v intf Data transfer interface
290 * @v format Format string
291 * @v args Arguments corresponding to the format string
292 * @ret rc Return status code
294 int xfer_vprintf ( struct interface *intf, const char *format,
301 /* Create temporary string */
302 va_copy ( args_tmp, args );
303 len = vasprintf ( &buf, format, args );
310 /* Transmit string */
311 if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 )
321 * Deliver formatted string
323 * @v intf Data transfer interface
324 * @v format Format string
325 * @v ... Arguments corresponding to the format string
326 * @ret rc Return status code
328 int xfer_printf ( struct interface *intf, const char *format, ... ) {
332 va_start ( args, format );
333 rc = xfer_vprintf ( intf, format, args );
341 * @v intf Data transfer interface
342 * @v offset Offset to new position
343 * @ret rc Return status code
345 int xfer_seek ( struct interface *intf, off_t offset ) {
346 struct io_buffer *iobuf;
347 struct xfer_metadata meta = {
348 .flags = XFER_FL_ABS_OFFSET,
352 DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n",
353 INTF_DBG ( intf ), offset );
355 /* Allocate and send a zero-length data buffer */
356 iobuf = xfer_alloc_iob ( intf, 0 );
360 return xfer_deliver ( intf, iobuf, &meta );
364 * Check that data is delivered strictly in order
366 * @v meta Data transfer metadata
367 * @v pos Current position
368 * @v len Length of data
369 * @ret rc Return status code
371 int xfer_check_order ( struct xfer_metadata *meta, size_t *pos, size_t len ) {
374 /* Allow out-of-order zero-length packets (as used by xfer_seek()) */
378 /* Calculate position of this delivery */
380 if ( meta->flags & XFER_FL_ABS_OFFSET )
382 new_pos += meta->offset;
384 /* Fail if delivery position is not equal to current position */
385 if ( new_pos != *pos )
388 /* Update current position */