|  | @@ -70,6 +70,10 @@ struct pinger {
 | 
		
	
		
			
			| 70 | 70 |  	uint16_t sequence;
 | 
		
	
		
			
			| 71 | 71 |  	/** Response for current sequence number is still pending */
 | 
		
	
		
			
			| 72 | 72 |  	int pending;
 | 
		
	
		
			
			|  | 73 | +	/** Number of remaining expiry events (zero to continue indefinitely) */
 | 
		
	
		
			
			|  | 74 | +	unsigned int remaining;
 | 
		
	
		
			
			|  | 75 | +	/** Return status */
 | 
		
	
		
			
			|  | 76 | +	int rc;
 | 
		
	
		
			
			| 73 | 77 |  
 | 
		
	
		
			
			| 74 | 78 |  	/** Callback function
 | 
		
	
		
			
			| 75 | 79 |  	 *
 | 
		
	
	
		
			
			|  | @@ -164,7 +168,12 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
 | 
		
	
		
			
			| 164 | 168 |  	/* If no response has been received, notify the callback function */
 | 
		
	
		
			
			| 165 | 169 |  	if ( pinger->pending )
 | 
		
	
		
			
			| 166 | 170 |  		pinger->callback ( NULL, pinger->sequence, 0, -ETIMEDOUT );
 | 
		
	
		
			
			| 167 |  | -	pinger->pending = 1;
 | 
		
	
		
			
			|  | 171 | +
 | 
		
	
		
			
			|  | 172 | +	/* Check for termination */
 | 
		
	
		
			
			|  | 173 | +	if ( pinger->remaining && ( --pinger->remaining == 0 ) ) {
 | 
		
	
		
			
			|  | 174 | +		pinger_close ( pinger, pinger->rc );
 | 
		
	
		
			
			|  | 175 | +		return;
 | 
		
	
		
			
			|  | 176 | +	}
 | 
		
	
		
			
			| 168 | 177 |  
 | 
		
	
		
			
			| 169 | 178 |  	/* Increase sequence number */
 | 
		
	
		
			
			| 170 | 179 |  	pinger->sequence++;
 | 
		
	
	
		
			
			|  | @@ -173,6 +182,7 @@ static void pinger_expired ( struct retry_timer *timer, int over __unused ) {
 | 
		
	
		
			
			| 173 | 182 |  	 * case the transmission attempt fails.
 | 
		
	
		
			
			| 174 | 183 |  	 */
 | 
		
	
		
			
			| 175 | 184 |  	start_timer_fixed ( &pinger->timer, pinger->timeout );
 | 
		
	
		
			
			|  | 185 | +	pinger->pending = 1;
 | 
		
	
		
			
			| 176 | 186 |  
 | 
		
	
		
			
			| 177 | 187 |  	/* Allocate I/O buffer */
 | 
		
	
		
			
			| 178 | 188 |  	iobuf = xfer_alloc_iob ( &pinger->xfer, pinger->len );
 | 
		
	
	
		
			
			|  | @@ -210,6 +220,7 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 210 | 220 |  			    struct xfer_metadata *meta ) {
 | 
		
	
		
			
			| 211 | 221 |  	size_t len = iob_len ( iobuf );
 | 
		
	
		
			
			| 212 | 222 |  	uint16_t sequence = meta->offset;
 | 
		
	
		
			
			|  | 223 | +	int terminate = 0;
 | 
		
	
		
			
			| 213 | 224 |  	int rc;
 | 
		
	
		
			
			| 214 | 225 |  
 | 
		
	
		
			
			| 215 | 226 |  	/* Clear response pending flag, if applicable */
 | 
		
	
	
		
			
			|  | @@ -218,18 +229,35 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 218 | 229 |  
 | 
		
	
		
			
			| 219 | 230 |  	/* Check for errors */
 | 
		
	
		
			
			| 220 | 231 |  	if ( len != pinger->len ) {
 | 
		
	
		
			
			|  | 232 | +		/* Incorrect length: terminate immediately if we are
 | 
		
	
		
			
			|  | 233 | +		 * not pinging indefinitely.
 | 
		
	
		
			
			|  | 234 | +		 */
 | 
		
	
		
			
			| 221 | 235 |  		DBGC ( pinger, "PINGER %p received incorrect length %zd "
 | 
		
	
		
			
			| 222 | 236 |  		       "(expected %zd)\n", pinger, len, pinger->len );
 | 
		
	
		
			
			| 223 | 237 |  		rc = -EPROTO_LEN;
 | 
		
	
		
			
			|  | 238 | +		terminate = ( pinger->remaining != 0 );
 | 
		
	
		
			
			| 224 | 239 |  	} else if ( ( rc = pinger_verify ( pinger, iobuf->data ) ) != 0 ) {
 | 
		
	
		
			
			|  | 240 | +		/* Incorrect data: terminate immediately if we are not
 | 
		
	
		
			
			|  | 241 | +		 * pinging indefinitely.
 | 
		
	
		
			
			|  | 242 | +		 */
 | 
		
	
		
			
			| 225 | 243 |  		DBGC ( pinger, "PINGER %p received incorrect data:\n", pinger );
 | 
		
	
		
			
			| 226 | 244 |  		DBGC_HDA ( pinger, 0, iobuf->data, iob_len ( iobuf ) );
 | 
		
	
		
			
			|  | 245 | +		terminate = ( pinger->remaining != 0 );
 | 
		
	
		
			
			| 227 | 246 |  	} else if ( sequence != pinger->sequence ) {
 | 
		
	
		
			
			|  | 247 | +		/* Incorrect sequence number (probably a delayed response):
 | 
		
	
		
			
			|  | 248 | +		 * report via callback but otherwise ignore.
 | 
		
	
		
			
			|  | 249 | +		 */
 | 
		
	
		
			
			| 228 | 250 |  		DBGC ( pinger, "PINGER %p received sequence %d (expected %d)\n",
 | 
		
	
		
			
			| 229 | 251 |  		       pinger, sequence, pinger->sequence );
 | 
		
	
		
			
			| 230 | 252 |  		rc = -EPROTO_SEQ;
 | 
		
	
		
			
			|  | 253 | +		terminate = 0;
 | 
		
	
		
			
			| 231 | 254 |  	} else {
 | 
		
	
		
			
			|  | 255 | +		/* Success: record that a packet was successfully received,
 | 
		
	
		
			
			|  | 256 | +		 * and terminate if we expect to send no further packets.
 | 
		
	
		
			
			|  | 257 | +		 */
 | 
		
	
		
			
			| 232 | 258 |  		rc = 0;
 | 
		
	
		
			
			|  | 259 | +		pinger->rc = 0;
 | 
		
	
		
			
			|  | 260 | +		terminate = ( pinger->remaining == 1 );
 | 
		
	
		
			
			| 233 | 261 |  	}
 | 
		
	
		
			
			| 234 | 262 |  
 | 
		
	
		
			
			| 235 | 263 |  	/* Discard I/O buffer */
 | 
		
	
	
		
			
			|  | @@ -238,6 +266,10 @@ static int pinger_deliver ( struct pinger *pinger, struct io_buffer *iobuf,
 | 
		
	
		
			
			| 238 | 266 |  	/* Notify callback function */
 | 
		
	
		
			
			| 239 | 267 |  	pinger->callback ( meta->src, sequence, len, rc );
 | 
		
	
		
			
			| 240 | 268 |  
 | 
		
	
		
			
			|  | 269 | +	/* Terminate if applicable */
 | 
		
	
		
			
			|  | 270 | +	if ( terminate )
 | 
		
	
		
			
			|  | 271 | +		pinger_close ( pinger, rc );
 | 
		
	
		
			
			|  | 272 | +
 | 
		
	
		
			
			| 241 | 273 |  	return rc;
 | 
		
	
		
			
			| 242 | 274 |  }
 | 
		
	
		
			
			| 243 | 275 |  
 | 
		
	
	
		
			
			|  | @@ -268,10 +300,11 @@ static struct interface_descriptor pinger_job_desc =
 | 
		
	
		
			
			| 268 | 300 |   * @v hostname		Hostname to ping
 | 
		
	
		
			
			| 269 | 301 |   * @v timeout		Timeout (in ticks)
 | 
		
	
		
			
			| 270 | 302 |   * @v len		Payload length
 | 
		
	
		
			
			|  | 303 | + * @v count		Number of packets to send (or zero for no limit)
 | 
		
	
		
			
			| 271 | 304 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 272 | 305 |   */
 | 
		
	
		
			
			| 273 | 306 |  int create_pinger ( struct interface *job, const char *hostname,
 | 
		
	
		
			
			| 274 |  | -		    unsigned long timeout, size_t len,
 | 
		
	
		
			
			|  | 307 | +		    unsigned long timeout, size_t len, unsigned int count,
 | 
		
	
		
			
			| 275 | 308 |  		    void ( * callback ) ( struct sockaddr *src,
 | 
		
	
		
			
			| 276 | 309 |  					  unsigned int sequence, size_t len,
 | 
		
	
		
			
			| 277 | 310 |  					  int rc ) ) {
 | 
		
	
	
		
			
			|  | @@ -292,7 +325,9 @@ int create_pinger ( struct interface *job, const char *hostname,
 | 
		
	
		
			
			| 292 | 325 |  	timer_init ( &pinger->timer, pinger_expired, &pinger->refcnt );
 | 
		
	
		
			
			| 293 | 326 |  	pinger->timeout = timeout;
 | 
		
	
		
			
			| 294 | 327 |  	pinger->len = len;
 | 
		
	
		
			
			|  | 328 | +	pinger->remaining = ( count ? ( count + 1 /* Initial packet */ ) : 0 );
 | 
		
	
		
			
			| 295 | 329 |  	pinger->callback = callback;
 | 
		
	
		
			
			|  | 330 | +	pinger->rc = -ETIMEDOUT;
 | 
		
	
		
			
			| 296 | 331 |  
 | 
		
	
		
			
			| 297 | 332 |  	/* Open socket */
 | 
		
	
		
			
			| 298 | 333 |  	if ( ( rc = xfer_open_named_socket ( &pinger->xfer, SOCK_ECHO, NULL,
 |