SatCat5
ip_ping.cc
1 // Copyright 2022-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/ip_ping.h>
7 #include <satcat5/ip_dispatch.h>
8 #include <satcat5/log.h>
9 #include <satcat5/timeref.h>
10 
11 using satcat5::ip::Ping;
12 namespace log = satcat5::log;
13 
14 Ping::Ping(satcat5::ip::Dispatch* iface)
15  : m_iface(iface)
16  , m_addr(iface, satcat5::ip::PROTO_ICMP)
17  , m_arp_tref(SATCAT5_CLOCK->now())
18  , m_arp_remct(0)
19  , m_icmp_remct(0)
20  , m_reply_rcvd(false)
21 {
22  // No other initialization required.
23 }
24 
25 #if SATCAT5_ALLOW_DELETION
26 Ping::~Ping() {
27  stop();
28 }
29 #endif
30 
31 void Ping::arping(const satcat5::ip::Addr& dstaddr, unsigned qty) {
32  stop(); // Reset internal state.
33  if (qty > 0) {
34  // Set initial state for ARP-ping.
35  m_addr.connect(dstaddr, satcat5::eth::MACADDR_NONE);
36  m_arp_remct = qty; // How many ARP queries?
37  m_icmp_remct = 0; // No ICMP queries
38  timer_every(1000); // Timer for follow-up
39  m_iface->arp()->add(this); // Register for callback
40  // Send the first ARP query.
41  send_arping();
42  }
43 }
44 
45 void Ping::ping(const satcat5::ip::Addr& dstaddr, unsigned qty) {
46  stop(); // Reset internal state.
47  if (qty > 0) {
48  // Set initial state for ICMP-ping.
49  m_arp_remct = 4; // Additional ARP attempts?
50  m_icmp_remct = qty; // How many ICMP queries?
51  timer_every(1000); // Timer for follow-up
52  m_iface->icmp()->add(this); // Register for callback
53  // Start address resolution.
54  m_addr.connect(dstaddr);
55  }
56 }
57 
58 void Ping::stop() {
59  // Reset internal state.
60  m_arp_remct = 0;
61  m_icmp_remct = 0;
62  timer_stop();
63  // Unregister callbacks (safe to remove even if not on list.)
64  m_iface->arp()->remove(this);
65  m_iface->icmp()->remove(this);
66 }
67 
69  const satcat5::eth::MacAddr& mac,
70  const satcat5::ip::Addr& ip)
71 {
72  if (ip == m_addr.dstaddr()) {
73  m_reply_rcvd = true;
74  u32 elapsed_usec = m_arp_tref.elapsed_usec();
75  log::Log(log::INFO, "Ping: Reply from").write(ip)
76  .write(", elapsed usec").write10(elapsed_usec);
77  }
78 }
79 
80 void Ping::ping_event(const satcat5::ip::Addr& from, u32 elapsed_usec) {
81  if (from == m_addr.dstaddr()) {
82  m_reply_rcvd = true;
83  log::Log(log::INFO, "Ping: Reply from").write(from)
84  .write(", elapsed usec").write10(elapsed_usec);
85  }
86 }
87 
88 void Ping::send_arping() {
89  // Send an ARP query to the stored address.
90  m_reply_rcvd = false;
91  m_arp_tref = SATCAT5_CLOCK->now();
92  m_iface->arp()->send_query(m_addr.dstaddr());
93 
94  // Decrement counter (unless unlimited).
95  if (m_arp_remct != Ping::UNLIMITED) {--m_arp_remct;}
96 }
97 
98 void Ping::send_ping() {
99  if (m_addr.ready()) {
100  // Send an ICMP query to the resolved address.
101  m_reply_rcvd = false;
102  m_arp_tref = SATCAT5_CLOCK->now();
103  m_iface->icmp()->send_ping(m_addr);
104  // Decrement counter (unless unlimited).
105  m_arp_remct = 0;
106  if (m_icmp_remct != Ping::UNLIMITED) {--m_icmp_remct;}
107  } else if (m_arp_remct > 0) {
108  // Re-attempt address resolution.
109  --m_arp_remct;
110  m_addr.retry();
111  } else {
112  // No ARP response after several attempts.
113  log::Log(log::INFO, "Ping: Gateway unreachable").write(m_addr.gateway());
114  stop();
115  }
116 }
117 
119  if (m_icmp_remct && m_arp_remct && m_addr.ready()) {
120  // No message after a successful ARP handshake.
121  } else if (!m_reply_rcvd) {
122  log::Log(log::INFO, "Ping: Request timed out.");
123  }
124 
125  if (m_icmp_remct) {
126  send_ping();
127  } else if (m_arp_remct) {
128  send_arping();
129  } else {
130  stop();
131  }
132 }
bool send_query(const satcat5::ip::Addr &target, const satcat5::eth::VlanTag &vtag=satcat5::eth::VTAG_NONE)
Send a query for a given IP address.
Definition: eth_arp.cc:112
void add(satcat5::eth::ArpListener *evt)
Register an event-listener.
Definition: eth_arp.h:76
void remove(satcat5::eth::ArpListener *evt)
Unregister an event-listener.
Definition: eth_arp.h:79
bool ready() const override
Is this address object ready for use? Child MUST override this method.
Definition: ip_address.h:68
void connect(const satcat5::ip::Addr &dstaddr, const satcat5::eth::VlanTag &vtag=satcat5::eth::VTAG_NONE)
Automatic address resolution using routing table + ARP.
Definition: ip_address.cc:54
void retry() override
If this Address is not in the ready() state, reattempt any steps required to do so,...
Definition: ip_address.cc:101
Protocol handler and dispatch unit for Internet Protocol v4 (IPv4).
Definition: ip_dispatch.h:43
Automatic "ping" functionality using an ICMP dispatch object A simplified wrapper for basic "ping" fu...
Definition: ip_ping.h:23
void arping(const satcat5::ip::Addr &dstaddr, unsigned qty=satcat5::ip::Ping::UNLIMITED)
Begin sending ARPING queries (ARP query).
Definition: ip_ping.cc:31
void timer_event() override
Child class MUST override this method.
Definition: ip_ping.cc:118
void ping_event(const satcat5::ip::Addr &from, u32 elapsed_usec) override
Callback method when a ping response is received.
Definition: ip_ping.cc:80
static constexpr unsigned UNLIMITED
All requests can send N queries or until told to stop.
Definition: ip_ping.h:30
void arp_event(const satcat5::eth::MacAddr &mac, const satcat5::ip::Addr &ip) override
Callback for any announced MAC/IP address pair.
Definition: ip_ping.cc:68
void stop()
Stop any ongoing activities.
Definition: ip_ping.cc:58
void ping(const satcat5::ip::Addr &dstaddr, unsigned qty=satcat5::ip::Ping::UNLIMITED)
Begin sending PING queries (ICMP echo request).
Definition: ip_ping.cc:45
void remove(satcat5::ip::PingListener *cb)
Add/remove callback handlers for Ping responses.
Definition: ip_icmp.h:118
void add(satcat5::ip::PingListener *cb)
Add/remove callback handlers for Ping responses.
Definition: ip_icmp.h:116
bool send_ping(satcat5::ip::Address &dst)
Initiate a ping (Echo request = Type 8.0).
Definition: ip_icmp.cc:151
The Log class creates and formats one log message.
Definition: log.h:195
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Definition: log.cc:261
Log & write(const char *str)
Formatting methods for various data types.
Definition: log.cc:198
void timer_stop()
Stop all future notifications.
Definition: polling.cc:326
void timer_every(unsigned msec)
Configure a repeating notification every X milliseconds.
Definition: polling.cc:321
Diagnostic logging to UART and/or Ethernet ports.
An Ethernet MAC address (with serializable interface).
Definition: eth_header.h:29
IPv4 address is a 32-bit unsigned integer.
Definition: ip_core.h:15
unsigned elapsed_usec() const
Elapsed time in microseconds.
Definition: timeref.cc:25
TimeRef and TimeVal define the API for monotonic timers.