diff options
-rw-r--r-- | src/core/pinger.c | 39 | ||||
-rw-r--r-- | src/hci/commands/ping_cmd.c | 7 | ||||
-rw-r--r-- | src/include/ipxe/pinger.h | 1 | ||||
-rw-r--r-- | src/include/usr/pingmgmt.h | 3 | ||||
-rw-r--r-- | src/usr/pingmgmt.c | 8 |
5 files changed, 51 insertions, 7 deletions
diff --git a/src/core/pinger.c b/src/core/pinger.c index 0312ff38..558cfb49 100644 --- a/src/core/pinger.c +++ b/src/core/pinger.c @@ -70,6 +70,10 @@ struct pinger { 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 * @@ -164,7 +168,12 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) { /* If no response has been received, notify the callback function */ if ( pinger->pending ) pinger->callback ( NULL, pinger->sequence, 0, -ETIMEDOUT ); - pinger->pending = 1; + + /* Check for termination */ + if ( pinger->remaining && ( --pinger->remaining == 0 ) ) { + pinger_close ( pinger, pinger->rc ); + return; + } /* Increase sequence number */ pinger->sequence++; @@ -173,6 +182,7 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) { * 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 ); @@ -210,6 +220,7 @@ 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 */ @@ -218,18 +229,35 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf, /* 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 */ @@ -238,6 +266,10 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf, /* Notify callback function */ pinger->callback ( meta->src, sequence, len, rc ); + /* Terminate if applicable */ + if ( terminate ) + pinger_close ( pinger, rc ); + return rc; } @@ -268,10 +300,11 @@ static struct interface_descriptor pinger_job_desc = * @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) * @ret rc Return status code */ int create_pinger ( struct interface *job, const char *hostname, - unsigned long timeout, size_t len, + unsigned long timeout, size_t len, unsigned int count, void ( * callback ) ( struct sockaddr *src, unsigned int sequence, size_t len, int rc ) ) { @@ -292,7 +325,9 @@ int create_pinger ( struct interface *job, const char *hostname, 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, diff --git a/src/hci/commands/ping_cmd.c b/src/hci/commands/ping_cmd.c index d514a2a2..92c5443a 100644 --- a/src/hci/commands/ping_cmd.c +++ b/src/hci/commands/ping_cmd.c @@ -48,6 +48,8 @@ struct ping_options { unsigned int size; /** Timeout (in ms) */ unsigned long timeout; + /** Number of packets to send (or zero for no limit) */ + unsigned int count; }; /** "ping" option list */ @@ -56,6 +58,8 @@ static struct option_descriptor ping_opts[] = { struct ping_options, size, parse_integer ), OPTION_DESC ( "timeout", 't', required_argument, struct ping_options, timeout, parse_timeout ), + OPTION_DESC ( "count", 'c', required_argument, + struct ping_options, count, parse_integer ), }; /** "ping" command descriptor */ @@ -87,7 +91,8 @@ static int ping_exec ( int argc, char **argv ) { hostname = argv[optind]; /* Ping */ - if ( ( rc = ping ( hostname, opts.timeout, opts.size ) ) != 0 ) + if ( ( rc = ping ( hostname, opts.timeout, opts.size, + opts.count ) ) != 0 ) return rc; return 0; diff --git a/src/include/ipxe/pinger.h b/src/include/ipxe/pinger.h index 2d840331..9932df6b 100644 --- a/src/include/ipxe/pinger.h +++ b/src/include/ipxe/pinger.h @@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern int create_pinger ( struct interface *job, const char *hostname, unsigned long timeout, size_t len, + unsigned int count, void ( * callback ) ( struct sockaddr *peer, unsigned int sequence, size_t len, diff --git a/src/include/usr/pingmgmt.h b/src/include/usr/pingmgmt.h index 45ad5d39..8bded384 100644 --- a/src/include/usr/pingmgmt.h +++ b/src/include/usr/pingmgmt.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> -extern int ping ( const char *hostname, unsigned long timeout, size_t len ); +extern int ping ( const char *hostname, unsigned long timeout, size_t len, + unsigned int count ); #endif /* _USR_PINGMGMT_H */ diff --git a/src/usr/pingmgmt.c b/src/usr/pingmgmt.c index cf6a5111..f8366f26 100644 --- a/src/usr/pingmgmt.c +++ b/src/usr/pingmgmt.c @@ -58,14 +58,16 @@ static void ping_callback ( struct sockaddr *peer, unsigned int sequence, * @v hostname Hostname * @v timeout Timeout between pings, in ticks * @v len Payload length + * @v count Number of packets to send (or zero for no limit) * @ret rc Return status code */ -int ping ( const char *hostname, unsigned long timeout, size_t len ) { +int ping ( const char *hostname, unsigned long timeout, size_t len, + unsigned int count ) { int rc; /* Create pinger */ - if ( ( rc = create_pinger ( &monojob, hostname, timeout, - len, ping_callback ) ) != 0 ) { + if ( ( rc = create_pinger ( &monojob, hostname, timeout, len, + count, ping_callback ) ) != 0 ) { printf ( "Could not start ping: %s\n", strerror ( rc ) ); return rc; } |