diff options
Diffstat (limited to 'qemu/roms/ipxe/src/core/pinger.c')
-rw-r--r-- | qemu/roms/ipxe/src/core/pinger.c | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/qemu/roms/ipxe/src/core/pinger.c b/qemu/roms/ipxe/src/core/pinger.c deleted file mode 100644 index 0ff7bb9f2..000000000 --- a/qemu/roms/ipxe/src/core/pinger.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <ipxe/refcnt.h> -#include <ipxe/interface.h> -#include <ipxe/job.h> -#include <ipxe/xfer.h> -#include <ipxe/iobuf.h> -#include <ipxe/open.h> -#include <ipxe/socket.h> -#include <ipxe/retry.h> -#include <ipxe/pinger.h> - -/** @file - * - * ICMP ping sender - * - */ - -/* Disambiguate the various error causes */ -#define EPROTO_LEN __einfo_error ( EINFO_EPROTO_LEN ) -#define EINFO_EPROTO_LEN __einfo_uniqify ( EINFO_EPROTO, 0x01, \ - "Incorrect reply length" ) -#define EPROTO_DATA __einfo_error ( EINFO_EPROTO_DATA ) -#define EINFO_EPROTO_DATA __einfo_uniqify ( EINFO_EPROTO, 0x02, \ - "Incorrect reply data" ) -#define EPROTO_SEQ __einfo_error ( EINFO_EPROTO_SEQ ) -#define EINFO_EPROTO_SEQ __einfo_uniqify ( EINFO_EPROTO, 0x03, \ - "Delayed or out-of-sequence reply" ) - -/** A pinger */ -struct pinger { - /** Reference count */ - struct refcnt refcnt; - - /** Job control interface */ - struct interface job; - /** Data transfer interface */ - struct interface xfer; - - /** Timer */ - struct retry_timer timer; - /** Timeout */ - unsigned long timeout; - - /** Payload length */ - size_t len; - /** Current sequence number */ - uint16_t sequence; - /** Response for current sequence number is still pending */ - int pending; - /** Number of remaining expiry events (zero to continue indefinitely) */ - unsigned int remaining; - /** Return status */ - int rc; - - /** Callback function - * - * @v src Source socket address, or NULL - * @v sequence Sequence number - * @v len Payload length - * @v rc Status code - */ - void ( * callback ) ( struct sockaddr *src, unsigned int sequence, - size_t len, int rc ); -}; - -/** - * Generate payload - * - * @v pinger Pinger - * @v data Data buffer - */ -static void pinger_generate ( struct pinger *pinger, void *data ) { - uint8_t *bytes = data; - unsigned int i; - - /* Generate byte sequence */ - for ( i = 0 ; i < pinger->len ; i++ ) - bytes[i] = ( i & 0xff ); -} - -/** - * Verify payload - * - * @v pinger Pinger - * @v data Data buffer - * @ret rc Return status code - */ -static int pinger_verify ( struct pinger *pinger, const void *data ) { - const uint8_t *bytes = data; - unsigned int i; - - /* Check byte sequence */ - for ( i = 0 ; i < pinger->len ; i++ ) { - if ( bytes[i] != ( i & 0xff ) ) - return -EPROTO_DATA; - } - - return 0; -} - -/** - * Close pinger - * - * @v pinger Pinger - * @v rc Reason for close - */ -static void pinger_close ( struct pinger *pinger, int rc ) { - - /* Stop timer */ - stop_timer ( &pinger->timer ); - - /* Shut down interfaces */ - intf_shutdown ( &pinger->xfer, rc ); - intf_shutdown ( &pinger->job, rc ); -} - -/** - * Handle data transfer window change - * - * @v pinger Pinger - */ -static void pinger_window_changed ( struct pinger *pinger ) { - - /* Do nothing if timer is already running */ - if ( timer_running ( &pinger->timer ) ) - return; - - /* Start timer when window opens for the first time */ - if ( xfer_window ( &pinger->xfer ) ) - start_timer_nodelay ( &pinger->timer ); -} - -/** - * Handle timer expiry - * - * @v timer Timer - * @v over Failure indicator - */ -static void pinger_expired ( struct retry_timer *timer, int over __unused ) { - struct pinger *pinger = container_of ( timer, struct pinger, timer ); - struct xfer_metadata meta; - struct io_buffer *iobuf; - int rc; - - /* If no response has been received, notify the callback function */ - if ( pinger->pending && pinger->callback ) - pinger->callback ( NULL, pinger->sequence, 0, -ETIMEDOUT ); - - /* Check for termination */ - if ( pinger->remaining && ( --pinger->remaining == 0 ) ) { - pinger_close ( pinger, pinger->rc ); - return; - } - - /* Increase sequence number */ - pinger->sequence++; - - /* Restart timer. Do this before attempting to transmit, in - * case the transmission attempt fails. - */ - start_timer_fixed ( &pinger->timer, pinger->timeout ); - pinger->pending = 1; - - /* Allocate I/O buffer */ - iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len ); - if ( ! iobuf ) { - DBGC ( pinger, "PINGER %p could not allocate I/O buffer\n", - pinger ); - return; - } - - /* Generate payload */ - pinger_generate ( pinger, iob_put ( iobuf, pinger->len ) ); - - /* Generate metadata */ - memset ( &meta, 0, sizeof ( meta ) ); - meta.flags = XFER_FL_ABS_OFFSET; - meta.offset = pinger->sequence; - - /* Transmit packet */ - if ( ( rc = xfer_deliver ( &pinger->xfer, iobuf, &meta ) ) != 0 ) { - DBGC ( pinger, "PINGER %p could not transmit: %s\n", - pinger, strerror ( rc ) ); - return; - } -} - -/** - * Handle received data - * - * @v pinger Pinger - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf, - struct xfer_metadata *meta ) { - size_t len = iob_len ( iobuf ); - uint16_t sequence = meta->offset; - int terminate = 0; - int rc; - - /* Clear response pending flag, if applicable */ - if ( sequence == pinger->sequence ) - pinger->pending = 0; - - /* Check for errors */ - if ( len != pinger->len ) { - /* Incorrect length: terminate immediately if we are - * not pinging indefinitely. - */ - DBGC ( pinger, "PINGER %p received incorrect length %zd " - "(expected %zd)\n", pinger, len, pinger->len ); - rc = -EPROTO_LEN; - terminate = ( pinger->remaining != 0 ); - } else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) { - /* Incorrect data: terminate immediately if we are not - * pinging indefinitely. - */ - DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger ); - DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) ); - terminate = ( pinger->remaining != 0 ); - } else if ( sequence != pinger->sequence ) { - /* Incorrect sequence number (probably a delayed response): - * report via callback but otherwise ignore. - */ - DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n", - pinger, sequence, pinger->sequence ); - rc = -EPROTO_SEQ; - terminate = 0; - } else { - /* Success: record that a packet was successfully received, - * and terminate if we expect to send no further packets. - */ - rc = 0; - pinger->rc = 0; - terminate = ( pinger->remaining == 1 ); - } - - /* Discard I/O buffer */ - free_iob ( iobuf ); - - /* Notify callback function, if applicable */ - if ( pinger->callback ) - pinger->callback ( meta->src, sequence, len, rc ); - - /* Terminate if applicable */ - if ( terminate ) - pinger_close ( pinger, rc ); - - return rc; -} - -/** Pinger data transfer interface operations */ -static struct interface_operation pinger_xfer_op[] = { - INTF_OP ( xfer_deliver, struct pinger *, pinger_deliver ), - INTF_OP ( xfer_window_changed, struct pinger *, pinger_window_changed ), - INTF_OP ( intf_close, struct pinger *, pinger_close ), -}; - -/** Pinger data transfer interface descriptor */ -static struct interface_descriptor pinger_xfer_desc = - INTF_DESC ( struct pinger, xfer, pinger_xfer_op ); - -/** Pinger job control interface operations */ -static struct interface_operation pinger_job_op[] = { - INTF_OP ( intf_close, struct pinger *, pinger_close ), -}; - -/** Pinger job control interface descriptor */ -static struct interface_descriptor pinger_job_desc = - INTF_DESC ( struct pinger, job, pinger_job_op ); - -/** - * Create pinger - * - * @v job Job control interface - * @v hostname Hostname to ping - * @v timeout Timeout (in ticks) - * @v len Payload length - * @v count Number of packets to send (or zero for no limit) - * @v callback Callback function (or NULL) - * @ret rc Return status code - */ -int create_pinger ( struct interface *job, const char *hostname, - unsigned long timeout, size_t len, unsigned int count, - void ( * callback ) ( struct sockaddr *src, - unsigned int sequence, size_t len, - int rc ) ) { - struct pinger *pinger; - int rc; - - /* Sanity check */ - if ( ! timeout ) - return -EINVAL; - - /* Allocate and initialise structure */ - pinger = zalloc ( sizeof ( *pinger ) ); - if ( ! pinger ) - return -ENOMEM; - ref_init ( &pinger->refcnt, NULL ); - intf_init ( &pinger->job, &pinger_job_desc, &pinger->refcnt ); - intf_init ( &pinger->xfer, &pinger_xfer_desc, &pinger->refcnt ); - timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt ); - pinger->timeout = timeout; - pinger->len = len; - pinger->remaining = ( count ? ( count + 1 /* Initial packet */ ) : 0 ); - pinger->callback = callback; - pinger->rc = -ETIMEDOUT; - - /* Open socket */ - if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL, - hostname, NULL ) ) != 0 ) { - DBGC ( pinger, "PINGER %p could not open socket: %s\n", - pinger, strerror ( rc ) ); - goto err; - } - - /* Attach parent interface, mortalise self, and return */ - intf_plug_plug ( &pinger->job, job ); - ref_put ( &pinger->refcnt ); - return 0; - - err: - pinger_close ( pinger, rc ); - ref_put ( &pinger->refcnt ); - return rc; -} |