90 lines
2.3 KiB
C
90 lines
2.3 KiB
C
#include "icmp_types.h"
|
|
#include "ping/ft_ping_flags.h"
|
|
#include "internal/ping/output.h"
|
|
|
|
/* Forward declarations */
|
|
static int extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
|
uint16_t *seq_out);
|
|
static void handle_echo_reply(struct ping_state *state,
|
|
const icmp_reply_t *reply);
|
|
static int extract_our_error(const icmp_reply_t *reply, uint16_t our_id,
|
|
icmp_offending_packet_t *out, uint16_t *seq_out);
|
|
static void handle_icmp_error(struct ping_state *state,
|
|
const icmp_reply_t *reply);
|
|
/* -------------------- */
|
|
|
|
void
|
|
ping_callback(const icmp_reply_t *reply, void *userdata)
|
|
{
|
|
struct ping_state *state;
|
|
|
|
state = (struct ping_state *)userdata;
|
|
if (ICMP_TYPE_ECHO_REPLY == reply->type)
|
|
handle_echo_reply(state, reply);
|
|
else if (ICMP_TYPE_TIME_EXCEEDED == reply->type
|
|
|| ICMP_TYPE_DEST_UNREACHABLE == reply->type)
|
|
handle_icmp_error(state, reply);
|
|
}
|
|
|
|
static int
|
|
extract_our_echo(const icmp_reply_t *reply, uint16_t our_id,
|
|
uint16_t *seq_out)
|
|
{
|
|
uint16_t id;
|
|
uint16_t seq;
|
|
|
|
if (0 > icmp_reply_id_seq(reply, &id, &seq))
|
|
return 0;
|
|
if (our_id != id)
|
|
return 0;
|
|
*seq_out = seq;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
handle_echo_reply(struct ping_state *state, const icmp_reply_t *reply)
|
|
{
|
|
uint16_t seq;
|
|
int64_t rtt;
|
|
|
|
if (0 == extract_our_echo(reply, state->id, &seq))
|
|
return;
|
|
rtt = ping_tracker_record_recv(state->tracker, seq, &reply->timestamp);
|
|
if (0 > rtt)
|
|
return;
|
|
ping_stats_update(state->stats, rtt);
|
|
if (HAS_FLAG(state->config->flags, FLAG_FLOOD))
|
|
ping_output_flood_erase();
|
|
else
|
|
ping_output_packet(reply, seq, rtt, state->config->packet_size,
|
|
state->config);
|
|
}
|
|
|
|
static int
|
|
extract_our_error(const icmp_reply_t *reply, uint16_t our_id,
|
|
icmp_offending_packet_t *out, uint16_t *seq_out)
|
|
{
|
|
if (0 > icmp_error_extract_offending(reply, out))
|
|
return 0;
|
|
if (ICMP_TYPE_ECHO_REQUEST != out->icmp_type)
|
|
return 0;
|
|
if (our_id != out->rest.echo.id)
|
|
return 0;
|
|
*seq_out = out->rest.echo.seq;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
handle_icmp_error(struct ping_state *state, const icmp_reply_t *reply)
|
|
{
|
|
icmp_offending_packet_t offending;
|
|
uint16_t seq;
|
|
|
|
if (0 == extract_our_error(reply, state->id, &offending, &seq))
|
|
return;
|
|
if (0 > ping_tracker_record_recv(state->tracker, seq, &reply->timestamp))
|
|
return;
|
|
state->nb_errors++;
|
|
if (!HAS_FLAG(state->config->flags, FLAG_QUIET))
|
|
ping_output_error(reply, &offending, seq, state->config);
|
|
}
|