iPXE
Data Structures | Defines | Functions | Variables
pinger.c File Reference

ICMP ping sender. More...

#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>

Go to the source code of this file.

Data Structures

struct  pinger
 A pinger. More...

Defines

#define EPROTO_LEN   __einfo_error ( EINFO_EPROTO_LEN )
#define EINFO_EPROTO_LEN
#define EPROTO_DATA   __einfo_error ( EINFO_EPROTO_DATA )
#define EINFO_EPROTO_DATA
#define EPROTO_SEQ   __einfo_error ( EINFO_EPROTO_SEQ )
#define EINFO_EPROTO_SEQ

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void pinger_generate (struct pinger *pinger, void *data)
 Generate payload.
static int pinger_verify (struct pinger *pinger, const void *data)
 Verify payload.
static void pinger_close (struct pinger *pinger, int rc)
 Close pinger.
static void pinger_window_changed (struct pinger *pinger)
 Handle data transfer window change.
static void pinger_expired (struct retry_timer *timer, int over __unused)
 Handle timer expiry.
static int pinger_deliver (struct pinger *pinger, struct io_buffer *iobuf, struct xfer_metadata *meta)
 Handle received data.
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))
 Create pinger.

Variables

static struct interface_operation pinger_xfer_op []
 Pinger data transfer interface operations.
static struct interface_descriptor pinger_xfer_desc
 Pinger data transfer interface descriptor.
static struct interface_operation pinger_job_op []
 Pinger job control interface operations.
static struct interface_descriptor pinger_job_desc
 Pinger job control interface descriptor.

Detailed Description

ICMP ping sender.

Definition in file pinger.c.


Define Documentation

Definition at line 46 of file pinger.c.

Referenced by pinger_deliver().

Value:
__einfo_uniqify ( EINFO_EPROTO, 0x01, \
                                           "Incorrect reply length" )

Definition at line 47 of file pinger.c.

Definition at line 49 of file pinger.c.

Referenced by pinger_verify().

Value:
__einfo_uniqify ( EINFO_EPROTO, 0x02, \
                                            "Incorrect reply data" )

Definition at line 50 of file pinger.c.

Definition at line 52 of file pinger.c.

Referenced by pinger_deliver().

Value:
__einfo_uniqify ( EINFO_EPROTO, 0x03, \
                                           "Delayed or out-of-sequence reply" )

Definition at line 53 of file pinger.c.


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void pinger_generate ( struct pinger pinger,
void *  data 
) [static]

Generate payload.

Parameters:
pingerPinger
dataData buffer

Definition at line 99 of file pinger.c.

References bytes, data, and pinger::len.

Referenced by pinger_expired().

                                                                  {
        uint8_t *bytes = data;
        unsigned int i;

        /* Generate byte sequence */
        for ( i = 0 ; i < pinger->len ; i++ )
                bytes[i] = ( i & 0xff );
}
static int pinger_verify ( struct pinger pinger,
const void *  data 
) [static]

Verify payload.

Parameters:
pingerPinger
dataData buffer
Return values:
rcReturn status code

Definition at line 115 of file pinger.c.

References bytes, data, EPROTO_DATA, and pinger::len.

Referenced by pinger_deliver().

                                                                     {
        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;
}
static void pinger_close ( struct pinger pinger,
int  rc 
) [static]

Close pinger.

Parameters:
pingerPinger
rcReason for close

Definition at line 134 of file pinger.c.

References intf_shutdown(), pinger::job, stop_timer(), pinger::timer, and pinger::xfer.

Referenced by create_pinger(), pinger_deliver(), and pinger_expired().

                                                           {

        /* Stop timer */
        stop_timer ( &pinger->timer );

        /* Shut down interfaces */
        intf_shutdown ( &pinger->xfer, rc );
        intf_shutdown ( &pinger->job, rc );
}
static void pinger_window_changed ( struct pinger pinger) [static]

Handle data transfer window change.

Parameters:
pingerPinger

Definition at line 149 of file pinger.c.

References start_timer_nodelay(), pinger::timer, pinger::xfer, and xfer_window().

                                                            {

        /* 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 );
}
static void pinger_expired ( struct retry_timer timer,
int over  __unused 
) [static]

Handle timer expiry.

Parameters:
timerTimer
overFailure indicator

Definition at line 166 of file pinger.c.

References pinger::callback, container_of, DBGC, ETIMEDOUT, xfer_metadata::flags, iob_put, pinger::len, memset(), NULL, xfer_metadata::offset, pinger::pending, pinger_close(), pinger_generate(), pinger::rc, rc, pinger::remaining, pinger::sequence, start_timer_fixed(), strerror(), pinger::timeout, pinger::timer, pinger::xfer, xfer_alloc_iob(), xfer_deliver(), and XFER_FL_ABS_OFFSET.

Referenced by create_pinger().

                                                                            {
        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;
        }
}
static int pinger_deliver ( struct pinger pinger,
struct io_buffer iobuf,
struct xfer_metadata meta 
) [static]

Handle received data.

Parameters:
pingerPinger
iobufI/O buffer
metaData transfer metadata
Return values:
rcReturn status code

Definition at line 223 of file pinger.c.

References pinger::callback, io_buffer::data, DBGC, DBGC_HDA, EPROTO_LEN, EPROTO_SEQ, free_iob(), iob_len(), pinger::len, len, xfer_metadata::offset, pinger::pending, pinger_close(), pinger_verify(), pinger::rc, rc, pinger::remaining, pinger::sequence, and xfer_metadata::src.

                                                         {
        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;
}
int create_pinger ( struct interface job,
const char *  hostname,
unsigned long  timeout,
size_t  len,
unsigned int  count,
void(*)(struct sockaddr *src, unsigned int sequence, size_t len, int rc callback 
)

Create pinger.

Parameters:
jobJob control interface
hostnameHostname to ping
timeoutTimeout (in ticks)
lenPayload length
countNumber of packets to send (or zero for no limit)
callbackCallback function (or NULL)
Return values:
rcReturn status code

Definition at line 312 of file pinger.c.

References pinger::callback, DBGC, EINVAL, ENOMEM, ETIMEDOUT, intf_init(), intf_plug_plug(), pinger::job, pinger::len, len, NULL, pinger_close(), pinger_expired(), pinger::rc, rc, ref_init, ref_put, pinger::refcnt, pinger::remaining, SOCK_ECHO, strerror(), pinger::timeout, timeout(), pinger::timer, pinger::xfer, xfer_open_named_socket(), and zalloc().

Referenced by ping().

                                                     {
        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;
}

Variable Documentation

Initial value:

Pinger data transfer interface operations.

Definition at line 282 of file pinger.c.

Initial value:

Pinger data transfer interface descriptor.

Definition at line 289 of file pinger.c.

Initial value:
 {
        INTF_OP ( intf_close, struct pinger *, pinger_close ),
}

Pinger job control interface operations.

Definition at line 293 of file pinger.c.

Initial value:

Pinger job control interface descriptor.

Definition at line 298 of file pinger.c.