mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge #18934
18934: shell/gnrc_icmpv6_echo: separate ICMPv6 echo sending / parsing from shell command r=benpicco a=benpicco Co-authored-by: Benjamin Valentin <benjamin.valentin@bht-berlin.de> Co-authored-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
This commit is contained in:
commit
e248f954e6
@ -48,6 +48,7 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
stm32f7508-dk \
|
||||
stm32g0316-disco \
|
||||
stm32l0538-disco \
|
||||
stm32mp157c-dk2 \
|
||||
telosb \
|
||||
waspmote-pro \
|
||||
yunjia-nrf51822 \
|
||||
|
@ -24,7 +24,9 @@
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/ipv6/hdr.h"
|
||||
#include "net/icmpv6.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -58,6 +60,49 @@ gnrc_pktsnip_t *gnrc_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
|
||||
void gnrc_icmpv6_echo_req_handle(gnrc_netif_t *netif, ipv6_hdr_t *ipv6_hdr,
|
||||
icmpv6_echo_t *echo, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Send out ICMPv6 echo request
|
||||
*
|
||||
* @param[in] netif The interface the echo request should be sent on.
|
||||
* @param[in] addr The destination address of the echo request
|
||||
* @param[in] id ID for the echo message in host byte-order
|
||||
* @param[in] seq Sequence number for the echo message in host byte-order
|
||||
* @param[in] ttl Hop limit of the echo request
|
||||
* @param[in] len Length of the payload
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int gnrc_icmpv6_echo_send(const gnrc_netif_t *netif, const ipv6_addr_t *addr,
|
||||
uint16_t id, uint16_t seq, uint8_t ttl, size_t len);
|
||||
|
||||
/**
|
||||
* @brief ICMPv6 echo response callback
|
||||
*
|
||||
* @param[in] pkt Packet containing the ICMPv6 response
|
||||
* @param[in] corrupt Offset of corrupt payload, -1 if no corruption detected
|
||||
* @param[in] rtt_us round-trip-time in µs (0 if this information is not available)
|
||||
* @param[in] ctx User supplied context
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
typedef int (*gnrc_icmpv6_echo_rsp_handle_cb_t)(gnrc_pktsnip_t *pkt,
|
||||
int corrupt, uint32_t rtt_us, void *ctx);
|
||||
/**
|
||||
* @brief Parse ICMPv6 echo response
|
||||
*
|
||||
* @param[in] pkt Incoming ICMPv6 packet
|
||||
* @param[in] len Expected echo response payload length
|
||||
* @param[in] cb Callback function to execute
|
||||
* @param[in] ctx Callback function context
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int gnrc_icmpv6_echo_rsp_handle(gnrc_pktsnip_t *pkt, size_t len,
|
||||
gnrc_icmpv6_echo_rsp_handle_cb_t cb, void *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -35,7 +35,7 @@ gnrc_pktsnip_t *gnrc_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 "id=%" PRIu16
|
||||
DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 " id=%" PRIu16
|
||||
", seq=%" PRIu16, type, id, seq);
|
||||
echo = (icmpv6_echo_t *)pkt->data;
|
||||
echo->id = byteorder_htons(id);
|
||||
@ -107,4 +107,121 @@ void gnrc_icmpv6_echo_req_handle(gnrc_netif_t *netif, ipv6_hdr_t *ipv6_hdr,
|
||||
}
|
||||
}
|
||||
|
||||
static void _fill_payload(uint8_t *buf, size_t len, uint32_t now)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
memcpy(buf, &now, sizeof(now));
|
||||
len -= sizeof(now);
|
||||
buf += sizeof(now);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
*buf++ = i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _check_payload(const void *buf, size_t len, uint32_t now,
|
||||
uint32_t *triptime, int *corrupt)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
const uint8_t *data = buf;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
*triptime = now - unaligned_get_u32(buf);
|
||||
len -= sizeof(uint32_t);
|
||||
data += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
if (*data++ != i++) {
|
||||
*corrupt = data - (uint8_t *)buf - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int gnrc_icmpv6_echo_send(const gnrc_netif_t *netif, const ipv6_addr_t *addr,
|
||||
uint16_t id, uint16_t seq, uint8_t ttl, size_t len)
|
||||
{
|
||||
int res = 0;
|
||||
gnrc_pktsnip_t *pkt, *tmp;
|
||||
ipv6_hdr_t *ipv6;
|
||||
uint8_t *databuf;
|
||||
|
||||
pkt = gnrc_icmpv6_echo_build(ICMPV6_ECHO_REQ, id, seq, NULL, len);
|
||||
if (pkt == NULL) {
|
||||
DEBUG("error: packet buffer full\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
databuf = (uint8_t *)(pkt->data) + sizeof(icmpv6_echo_t);
|
||||
tmp = gnrc_ipv6_hdr_build(pkt, NULL, addr);
|
||||
if (tmp == NULL) {
|
||||
puts("error: packet buffer full");
|
||||
goto error_exit;
|
||||
}
|
||||
pkt = tmp;
|
||||
ipv6 = pkt->data;
|
||||
/* if ttl is unset (i.e. 0) gnrc_ipv6 will select hop limit */
|
||||
ipv6->hl = ttl;
|
||||
if (netif != NULL) {
|
||||
tmp = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (tmp == NULL) {
|
||||
DEBUG("error: packet buffer full");
|
||||
res = -ENOMEM;
|
||||
goto error_exit;
|
||||
}
|
||||
gnrc_netif_hdr_set_netif(tmp->data, netif);
|
||||
pkt = gnrc_pkt_prepend(pkt, tmp);
|
||||
}
|
||||
|
||||
/* add TX timestamp & test data */
|
||||
_fill_payload(databuf, len, ztimer_now(ZTIMER_USEC));
|
||||
|
||||
res = !gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt);
|
||||
if (res) {
|
||||
DEBUG("error: unable to send ICMPv6 echo request\n");
|
||||
res = -EBADF;
|
||||
}
|
||||
|
||||
error_exit:
|
||||
if (res) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int gnrc_icmpv6_echo_rsp_handle(gnrc_pktsnip_t *pkt, size_t len,
|
||||
gnrc_icmpv6_echo_rsp_handle_cb_t cb, void *ctx)
|
||||
{
|
||||
gnrc_pktsnip_t *ipv6, *icmpv6;
|
||||
ipv6_hdr_t *ipv6_hdr;
|
||||
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||
uint32_t triptime = 0;
|
||||
int corrupted = -1;
|
||||
|
||||
ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
icmpv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_ICMPV6);
|
||||
if ((ipv6 == NULL) || (icmpv6 == NULL)) {
|
||||
DEBUG("No IPv6 or ICMPv6 header found in reply");
|
||||
return -EINVAL;
|
||||
}
|
||||
ipv6_hdr = ipv6->data;
|
||||
#ifdef MODULE_GNRC_IPV6_NIB
|
||||
/* successful ping to neighbor (NIB handles case if ipv6->src is not a
|
||||
* neighbor) can be taken as upper-layer hint for reachability:
|
||||
* https://tools.ietf.org/html/rfc4861#section-7.3.1 */
|
||||
gnrc_ipv6_nib_nc_mark_reachable(&ipv6_hdr->src);
|
||||
#endif
|
||||
|
||||
icmpv6_echo_t *icmpv6_hdr = icmpv6->data;
|
||||
_check_payload(icmpv6_hdr + 1, len, now, &triptime, &corrupted);
|
||||
|
||||
return cb(pkt, corrupted, triptime, ctx);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -80,9 +80,7 @@ typedef struct {
|
||||
static void _usage(char *cmdname);
|
||||
static int _configure(int argc, char **argv, _ping_data_t *data);
|
||||
static void _pinger(_ping_data_t *data);
|
||||
static void _print_reply(_ping_data_t *data, gnrc_pktsnip_t *icmpv6, uint32_t now_us,
|
||||
ipv6_addr_t *from, unsigned hoplimit, gnrc_netif_hdr_t *netif_hdr);
|
||||
static void _handle_reply(_ping_data_t *data, gnrc_pktsnip_t *pkt, uint32_t now_us);
|
||||
static int _print_reply(gnrc_pktsnip_t *pkt, int corrupted, uint32_t rtt, void *ctx);
|
||||
static int _finish(_ping_data_t *data);
|
||||
|
||||
static int _gnrc_icmpv6_ping(int argc, char **argv)
|
||||
@ -110,7 +108,8 @@ static int _gnrc_icmpv6_ping(int argc, char **argv)
|
||||
msg_receive(&msg);
|
||||
switch (msg.type) {
|
||||
case GNRC_NETAPI_MSG_TYPE_RCV: {
|
||||
_handle_reply(&data, msg.content.ptr, ztimer_now(ZTIMER_USEC));
|
||||
gnrc_icmpv6_echo_rsp_handle(msg.content.ptr, data.datalen,
|
||||
_print_reply, &data);
|
||||
gnrc_pktbuf_release(msg.content.ptr);
|
||||
break;
|
||||
}
|
||||
@ -238,50 +237,10 @@ static int _configure(int argc, char **argv, _ping_data_t *data)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void _fill_payload(uint8_t *buf, size_t len)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||
memcpy(buf, &now, sizeof(now));
|
||||
len -= sizeof(now);
|
||||
buf += sizeof(now);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
*buf++ = i++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _check_payload(const void *buf, size_t len, uint32_t now,
|
||||
uint32_t *triptime, uint16_t *corrupt)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
const uint8_t *data = buf;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
*triptime = now - unaligned_get_u32(buf);
|
||||
len -= sizeof(uint32_t);
|
||||
data += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
if (*data++ != i++) {
|
||||
*corrupt = data - (uint8_t *)buf - 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _pinger(_ping_data_t *data)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt, *tmp;
|
||||
ipv6_hdr_t *ipv6;
|
||||
uint32_t timer;
|
||||
uint8_t *databuf;
|
||||
int res;
|
||||
|
||||
/* schedule next event (next ping or finish) ASAP */
|
||||
if ((data->num_sent + 1) < data->count) {
|
||||
@ -307,150 +266,111 @@ static void _pinger(_ping_data_t *data)
|
||||
ztimer_set_msg(ZTIMER_USEC, &data->sched_timer, timer, &data->sched_msg,
|
||||
thread_getpid());
|
||||
bf_unset(data->cktab, (size_t)data->num_sent % CKTAB_SIZE);
|
||||
pkt = gnrc_icmpv6_echo_build(ICMPV6_ECHO_REQ, data->id,
|
||||
(uint16_t)data->num_sent++,
|
||||
NULL, data->datalen);
|
||||
if (pkt == NULL) {
|
||||
puts("error: packet buffer full");
|
||||
return;
|
||||
}
|
||||
databuf = (uint8_t *)(pkt->data) + sizeof(icmpv6_echo_t);
|
||||
tmp = gnrc_ipv6_hdr_build(pkt, NULL, &data->host);
|
||||
if (tmp == NULL) {
|
||||
puts("error: packet buffer full");
|
||||
goto error_exit;
|
||||
}
|
||||
pkt = tmp;
|
||||
ipv6 = pkt->data;
|
||||
/* if data->hoplimit is unset (i.e. 0) gnrc_ipv6 will select hop limit */
|
||||
ipv6->hl = data->hoplimit;
|
||||
if (data->netif != NULL) {
|
||||
tmp = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (tmp == NULL) {
|
||||
puts("error: packet buffer full");
|
||||
goto error_exit;
|
||||
}
|
||||
gnrc_netif_hdr_set_netif(tmp->data, data->netif);
|
||||
pkt = gnrc_pkt_prepend(pkt, tmp);
|
||||
}
|
||||
|
||||
/* add TX timestamp & test data */
|
||||
_fill_payload(databuf, data->datalen);
|
||||
|
||||
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt)) {
|
||||
puts("error: unable to send ICMPv6 echo request");
|
||||
goto error_exit;
|
||||
res = gnrc_icmpv6_echo_send(data->netif, &data->host, data->id,
|
||||
data->num_sent++, data->hoplimit, data->datalen);
|
||||
switch (-res) {
|
||||
case 0:
|
||||
break;
|
||||
case ENOMEM:
|
||||
puts("error: packet buffer full");
|
||||
break;
|
||||
default:
|
||||
printf("error: %d\n", res);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
error_exit:
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
|
||||
static void _print_reply(_ping_data_t *data, gnrc_pktsnip_t *icmpv6, uint32_t now,
|
||||
ipv6_addr_t *from, unsigned hoplimit,
|
||||
gnrc_netif_hdr_t *netif_hdr)
|
||||
static int _print_reply(gnrc_pktsnip_t *pkt, int corrupted, uint32_t triptime, void *ctx)
|
||||
{
|
||||
_ping_data_t *data = ctx;
|
||||
gnrc_pktsnip_t *netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
|
||||
gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
gnrc_pktsnip_t *icmpv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_ICMPV6);
|
||||
|
||||
ipv6_hdr_t *ipv6_hdr = ipv6->data;
|
||||
icmpv6_echo_t *icmpv6_hdr = icmpv6->data;
|
||||
|
||||
kernel_pid_t if_pid = netif_hdr ? netif_hdr->if_pid : KERNEL_PID_UNDEF;
|
||||
int16_t rssi = netif_hdr ? netif_hdr->rssi : GNRC_NETIF_HDR_NO_RSSI;
|
||||
kernel_pid_t if_pid = KERNEL_PID_UNDEF;
|
||||
int16_t rssi = GNRC_NETIF_HDR_NO_RSSI;
|
||||
int16_t truncated;
|
||||
|
||||
if (netif) {
|
||||
gnrc_netif_hdr_t *netif_hdr = netif->data;
|
||||
if_pid = netif_hdr->if_pid;
|
||||
rssi = netif_hdr->rssi;
|
||||
}
|
||||
|
||||
/* check if payload size matches expectation */
|
||||
truncated = (data->datalen + sizeof(icmpv6_echo_t)) - icmpv6->size;
|
||||
|
||||
if (icmpv6_hdr->type == ICMPV6_ECHO_REP) {
|
||||
char from_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
const char *dupmsg = " (DUP!)";
|
||||
uint32_t triptime = 0;
|
||||
uint16_t recv_seq;
|
||||
uint16_t corrupted;
|
||||
|
||||
/* not our ping */
|
||||
if (byteorder_ntohs(icmpv6_hdr->id) != data->id) {
|
||||
return;
|
||||
}
|
||||
if (!ipv6_addr_is_multicast(&data->host) &&
|
||||
!ipv6_addr_equal(from, &data->host)) {
|
||||
return;
|
||||
}
|
||||
recv_seq = byteorder_ntohs(icmpv6_hdr->seq);
|
||||
ipv6_addr_to_str(&from_str[0], from, sizeof(from_str));
|
||||
|
||||
if (gnrc_netif_highlander() || (if_pid == KERNEL_PID_UNDEF) ||
|
||||
!ipv6_addr_is_link_local(from)) {
|
||||
printf("%u bytes from %s: icmp_seq=%u ttl=%u",
|
||||
(unsigned)icmpv6->size,
|
||||
from_str, recv_seq, hoplimit);
|
||||
} else {
|
||||
printf("%u bytes from %s%%%u: icmp_seq=%u ttl=%u",
|
||||
(unsigned)icmpv6->size,
|
||||
from_str, if_pid, recv_seq, hoplimit);
|
||||
|
||||
}
|
||||
/* check if payload size matches */
|
||||
if (truncated) {
|
||||
printf(" truncated by %d byte", truncated);
|
||||
}
|
||||
/* check response for corruption */
|
||||
else if (_check_payload(icmpv6_hdr + 1, data->datalen, now,
|
||||
&triptime, &corrupted)) {
|
||||
printf(" corrupted at offset %u", corrupted);
|
||||
}
|
||||
if (rssi != GNRC_NETIF_HDR_NO_RSSI) {
|
||||
printf(" rssi=%"PRId16" dBm", rssi);
|
||||
}
|
||||
/* we can only calculate RTT (triptime) if payload was large enough for
|
||||
a TX timestamp */
|
||||
if (data->datalen >= sizeof(uint32_t)) {
|
||||
printf(" time=%lu.%03lu ms", (long unsigned)triptime / 1000,
|
||||
(long unsigned)triptime % 1000);
|
||||
|
||||
data->tsum += triptime;
|
||||
if (triptime < data->tmin) {
|
||||
data->tmin = triptime;
|
||||
}
|
||||
if (triptime > data->tmax) {
|
||||
data->tmax = triptime;
|
||||
}
|
||||
}
|
||||
if (bf_isset(data->cktab, recv_seq % CKTAB_SIZE)) {
|
||||
data->num_rept++;
|
||||
}
|
||||
else {
|
||||
bf_set(data->cktab, recv_seq % CKTAB_SIZE);
|
||||
data->num_recv++;
|
||||
dupmsg += 7;
|
||||
}
|
||||
|
||||
puts(dupmsg);
|
||||
if (icmpv6_hdr->type != ICMPV6_ECHO_REP) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void _handle_reply(_ping_data_t *data, gnrc_pktsnip_t *pkt, uint32_t now)
|
||||
{
|
||||
gnrc_pktsnip_t *netif, *ipv6, *icmpv6;
|
||||
gnrc_netif_hdr_t *netif_hdr;
|
||||
ipv6_hdr_t *ipv6_hdr;
|
||||
char from_str[IPV6_ADDR_MAX_STR_LEN];
|
||||
const char *dupmsg = " (DUP!)";
|
||||
uint16_t recv_seq;
|
||||
|
||||
netif = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_NETIF);
|
||||
ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
icmpv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_ICMPV6);
|
||||
if ((ipv6 == NULL) || (icmpv6 == NULL)) {
|
||||
puts("No IPv6 or ICMPv6 header found in reply");
|
||||
return;
|
||||
/* not our ping */
|
||||
if (byteorder_ntohs(icmpv6_hdr->id) != data->id) {
|
||||
return -EINVAL;
|
||||
}
|
||||
ipv6_hdr = ipv6->data;
|
||||
netif_hdr = netif ? netif->data : NULL;
|
||||
_print_reply(data, icmpv6, now, &ipv6_hdr->src, ipv6_hdr->hl, netif_hdr);
|
||||
#ifdef MODULE_GNRC_IPV6_NIB
|
||||
/* successful ping to neighbor (NIB handles case if ipv6->src is not a
|
||||
* neighbor) can be taken as upper-layer hint for reachability:
|
||||
* https://tools.ietf.org/html/rfc4861#section-7.3.1 */
|
||||
gnrc_ipv6_nib_nc_mark_reachable(&ipv6_hdr->src);
|
||||
#endif
|
||||
if (!ipv6_addr_is_multicast(&data->host) &&
|
||||
!ipv6_addr_equal(&ipv6_hdr->src, &data->host)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
recv_seq = byteorder_ntohs(icmpv6_hdr->seq);
|
||||
ipv6_addr_to_str(&from_str[0], &ipv6_hdr->src, sizeof(from_str));
|
||||
|
||||
if (gnrc_netif_highlander() || (if_pid == KERNEL_PID_UNDEF) ||
|
||||
!ipv6_addr_is_link_local(&ipv6_hdr->src)) {
|
||||
printf("%u bytes from %s: icmp_seq=%u ttl=%u",
|
||||
(unsigned)icmpv6->size,
|
||||
from_str, recv_seq, ipv6_hdr->hl);
|
||||
} else {
|
||||
printf("%u bytes from %s%%%u: icmp_seq=%u ttl=%u",
|
||||
(unsigned)icmpv6->size,
|
||||
from_str, if_pid, recv_seq, ipv6_hdr->hl);
|
||||
|
||||
}
|
||||
/* check if payload size matches */
|
||||
if (truncated) {
|
||||
printf(" truncated by %d byte", truncated);
|
||||
}
|
||||
/* check response for corruption */
|
||||
else if (corrupted >= 0) {
|
||||
printf(" corrupted at offset %u", corrupted);
|
||||
}
|
||||
if (rssi != GNRC_NETIF_HDR_NO_RSSI) {
|
||||
printf(" rssi=%"PRId16" dBm", rssi);
|
||||
}
|
||||
/* we can only calculate RTT (triptime) if payload was large enough for
|
||||
a TX timestamp */
|
||||
if (triptime) {
|
||||
printf(" time=%lu.%03lu ms", (long unsigned)triptime / 1000,
|
||||
(long unsigned)triptime % 1000);
|
||||
|
||||
data->tsum += triptime;
|
||||
if (triptime < data->tmin) {
|
||||
data->tmin = triptime;
|
||||
}
|
||||
if (triptime > data->tmax) {
|
||||
data->tmax = triptime;
|
||||
}
|
||||
}
|
||||
if (bf_isset(data->cktab, recv_seq % CKTAB_SIZE)) {
|
||||
data->num_rept++;
|
||||
}
|
||||
else {
|
||||
bf_set(data->cktab, recv_seq % CKTAB_SIZE);
|
||||
data->num_recv++;
|
||||
dupmsg += 7;
|
||||
}
|
||||
|
||||
puts(dupmsg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _finish(_ping_data_t *data)
|
||||
|
Loading…
Reference in New Issue
Block a user