summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/pinger.c39
-rw-r--r--src/hci/commands/ping_cmd.c7
-rw-r--r--src/include/ipxe/pinger.h1
-rw-r--r--src/include/usr/pingmgmt.h3
-rw-r--r--src/usr/pingmgmt.c8
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;
}