These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / core / xfer.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
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.
8  *
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.
13  *
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
17  * 02110-1301, USA.
18  *
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.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <ipxe/iobuf.h>
31 #include <ipxe/xfer.h>
32 #include <ipxe/open.h>
33
34 /** @file
35  *
36  * Data transfer interfaces
37  *
38  */
39
40 /**
41  * Dummy transfer metadata
42  *
43  * This gets passed to xfer_interface::deliver() and equivalents when
44  * no metadata is available.
45  */
46 static struct xfer_metadata dummy_metadata;
47
48 /*****************************************************************************
49  *
50  * Data transfer interface operations
51  *
52  */
53
54 /**
55  * Send redirection event
56  *
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
61  */
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 );
68         int rc;
69
70         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect\n",
71                INTF_INTF_DBG ( intf, dest ) );
72
73         if ( op ) {
74                 rc = op ( object, type, args );
75         } else {
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
83                  * the parent.
84                  */
85                 intf_plug ( &tmp, dest );
86                 rc = xfer_vreopen ( dest, type, args );
87                 if ( rc == 0 ) {
88                         xfer_window_changed ( dest );
89                         xfer_window_changed ( &tmp );
90                 }
91                 intf_unplug ( &tmp );
92         }
93
94         if ( rc != 0 ) {
95                 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " redirect "
96                        "failed: %s\n", INTF_INTF_DBG ( intf, dest ),
97                        strerror ( rc ) );
98         }
99
100         intf_put ( dest );
101         return rc;
102 }
103
104 /**
105  * Check flow control window
106  *
107  * @v intf              Data transfer interface
108  * @ret len             Length of window
109  */
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 );
115         size_t len;
116
117         if ( op ) {
118                 len = op ( object );
119         } else {
120                 /* Default is to provide an unlimited window */
121                 len = ~( ( size_t ) 0 );
122         }
123
124         intf_put ( dest );
125         return len;
126 }
127
128 /**
129  * Report change of flow control window
130  *
131  * @v intf              Data transfer interface
132  *
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.
139  */
140 void xfer_window_changed ( struct interface *intf ) {
141
142         intf_poke ( intf, xfer_window_changed );
143 }
144
145 /**
146  * Allocate I/O buffer
147  *
148  * @v intf              Data transfer interface
149  * @v len               I/O buffer payload length
150  * @ret iobuf           I/O buffer
151  */
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;
158
159         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob %zd\n",
160                INTF_INTF_DBG ( intf, dest ), len );
161
162         if ( op ) {
163                 iobuf = op ( object, len );
164         } else {
165                 /* Default is to allocate an I/O buffer with no
166                  * reserved space.
167                  */
168                 iobuf = alloc_iob ( len );
169         }
170
171         if ( ! iobuf ) {
172                 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " alloc_iob "
173                        "failed\n", INTF_INTF_DBG ( intf, dest ) );
174         }
175
176         intf_put ( dest );
177         return iobuf;
178 }
179
180 /**
181  * Deliver datagram
182  *
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
187  */
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 );
195         int rc;
196
197         DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " deliver %zd\n",
198                INTF_INTF_DBG ( intf, dest ), iob_len ( iobuf ) );
199
200         if ( op ) {
201                 rc = op ( object, iobuf, meta );
202         } else {
203                 /* Default is to discard the I/O buffer */
204                 free_iob ( iobuf );
205                 rc = -EPIPE;
206         }
207
208         if ( rc != 0 ) {
209                 DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT
210                        " deliver failed: %s\n",
211                        INTF_INTF_DBG ( intf, dest ), strerror ( rc ) );
212         }
213
214         intf_put ( dest );
215         return rc;
216 }
217
218 /*****************************************************************************
219  *
220  * Data transfer interface helper functions
221  *
222  */
223
224 /**
225  * Send redirection event
226  *
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
231  */
232 int xfer_redirect ( struct interface *intf, int type, ... ) {
233         va_list args;
234         int rc;
235
236         va_start ( args, type );
237         rc = xfer_vredirect ( intf, type, args );
238         va_end ( args );
239         return rc;
240 }
241
242 /**
243  * Deliver datagram as I/O buffer without metadata
244  *
245  * @v intf              Data transfer interface
246  * @v iobuf             Datagram I/O buffer
247  * @ret rc              Return status code
248  */
249 int xfer_deliver_iob ( struct interface *intf, struct io_buffer *iobuf ) {
250         return xfer_deliver ( intf, iobuf, &dummy_metadata );
251 }
252
253 /**
254  * Deliver datagram as raw data
255  *
256  * @v intf              Data transfer interface
257  * @v data              Data
258  * @v len               Length of data
259  * @v meta              Data transfer metadata
260  * @ret rc              Return status code
261  */
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;
265
266         iobuf = xfer_alloc_iob ( intf, len );
267         if ( ! iobuf )
268                 return -ENOMEM;
269
270         memcpy ( iob_put ( iobuf, len ), data, len );
271         return xfer_deliver ( intf, iobuf, meta );
272 }
273
274 /**
275  * Deliver datagram as raw data without metadata
276  *
277  * @v intf              Data transfer interface
278  * @v data              Data
279  * @v len               Length of data
280  * @ret rc              Return status code
281  */
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 );
284 }
285
286 /**
287  * Deliver formatted string
288  *
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
293  */
294 int xfer_vprintf ( struct interface *intf, const char *format,
295                    va_list args ) {
296         va_list args_tmp;
297         char *buf;
298         int len;
299         int rc;
300
301         /* Create temporary string */
302         va_copy ( args_tmp, args );
303         len = vasprintf ( &buf, format, args );
304         if ( len < 0 ) {
305                 rc = len;
306                 goto err_asprintf;
307         }
308         va_end ( args_tmp );
309
310         /* Transmit string */
311         if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 )
312                 goto err_deliver;
313
314  err_deliver:
315         free ( buf );
316  err_asprintf:
317         return rc;
318 }
319
320 /**
321  * Deliver formatted string
322  *
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
327  */
328 int xfer_printf ( struct interface *intf, const char *format, ... ) {
329         va_list args;
330         int rc;
331
332         va_start ( args, format );
333         rc = xfer_vprintf ( intf, format, args );
334         va_end ( args );
335         return rc;
336 }
337
338 /**
339  * Seek to position
340  *
341  * @v intf              Data transfer interface
342  * @v offset            Offset to new position
343  * @ret rc              Return status code
344  */
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,
349                 .offset = offset,
350         };
351
352         DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " seek to %ld\n",
353                INTF_DBG ( intf ), offset );
354
355         /* Allocate and send a zero-length data buffer */
356         iobuf = xfer_alloc_iob ( intf, 0 );
357         if ( ! iobuf )
358                 return -ENOMEM;
359
360         return xfer_deliver ( intf, iobuf, &meta );
361 }
362
363 /**
364  * Check that data is delivered strictly in order
365  *
366  * @v meta              Data transfer metadata
367  * @v pos               Current position
368  * @v len               Length of data
369  * @ret rc              Return status code
370  */
371 int xfer_check_order ( struct xfer_metadata *meta, size_t *pos, size_t len ) {
372         size_t new_pos;
373
374         /* Allow out-of-order zero-length packets (as used by xfer_seek()) */
375         if ( len == 0 )
376                 return 0;
377
378         /* Calculate position of this delivery */
379         new_pos = *pos;
380         if ( meta->flags & XFER_FL_ABS_OFFSET )
381                 new_pos = 0;
382         new_pos += meta->offset;
383
384         /* Fail if delivery position is not equal to current position */
385         if ( new_pos != *pos )
386                 return -EPROTO;
387
388         /* Update current position */
389         *pos += len;
390
391         return 0;
392 }