6 #include <satcat5/ip_address.h>
7 #include <satcat5/ip_dispatch.h>
8 #include <satcat5/ip_icmp.h>
14 #ifndef SATCAT5_ICMP_DETAIL
15 #define SATCAT5_ICMP_DETAIL 1
19 #ifndef SATCAT5_ICMP_LOG_COOLDOWN
20 #define SATCAT5_ICMP_LOG_COOLDOWN 500
25 namespace ip = satcat5::ip;
26 namespace log = satcat5::log;
29 static constexpr
Type TYPE_ICMP =
Type(ip::PROTO_ICMP);
34 static constexpr u32 TIMESTAMP_ARB = (1u << 31);
37 static constexpr
unsigned ECHO_WORDS = 4;
38 static constexpr
unsigned TIME_WORDS = 10;
41 static inline const char* code2msg(u16 code) {
42 if (SATCAT5_ICMP_DETAIL >= 2) {
44 if (code == ip::ICMP_FRAG_REQUIRED)
45 return "Fragmentation required but DF set";
46 if (code == ip::ICMP_SRC_ROUTE_FAILED)
47 return "Source route failed";
48 if (code == ip::ICMP_DST_NET_UNKNOWN)
49 return "Destination network unknown";
50 if (code == ip::ICMP_DST_HOST_UNKNOWN)
51 return "Destination host unknown";
52 if (code == ip::ICMP_SRC_HOST_ISOLATED)
53 return "Source host isolated";
54 if (code == ip::ICMP_NET_PROHIBITED)
55 return "Network administratively prohibited";
56 if (code == ip::ICMP_HOST_PROHIBITED)
57 return "Host administratively prohibited";
58 if (code == ip::ICMP_TOS_NET)
59 return "Network unreachable for ToS";
60 if (code == ip::ICMP_TOS_HOST)
61 return "Host unreachable for ToS";
62 if (code == ip::ICMP_COMM_PROHIBITED)
63 return "Communication administratively prohibited";
64 if (code == ip::ICMP_HOST_PRECEDENCE)
65 return "Host precedence violation";
66 if (code == ip::ICMP_PRECEDENCE_CUTOFF)
67 return "Precedence cutoff in effect";
68 if (code == ip::ICMP_FRAG_TIMEOUT)
69 return "Fragment reassembly time exceeded";
70 if (code == ip::ICMP_IP_HDR_POINTER)
71 return "IP Header: Pointer error";
72 if (code == ip::ICMP_IP_HDR_OPTION)
73 return "IP Header: Missing required option";
74 if (code == ip::ICMP_IP_HDR_LENGTH)
75 return "IP Header: Bad length";
78 if (SATCAT5_ICMP_DETAIL >= 1) {
80 if (code == ip::ICMP_UNREACHABLE_NET)
81 return "Destination network unreachable";
82 if (code == ip::ICMP_UNREACHABLE_HOST)
83 return "Destination host unreachable";
84 if (code == ip::ICMP_UNREACHABLE_PROTO)
85 return "Destination protocol unreachable";
86 if (code == ip::ICMP_UNREACHABLE_PORT)
87 return "Destination port unreachable";
88 if (code == ip::ICMP_TTL_EXPIRED)
89 return "TTL expired in transit";
93 u16 type = code & ip::ICMP_TYPE_MASK;
94 if (type == ip::ICMP_TYPE_UNREACHABLE)
95 return "Destination unreachable";
96 if (type == ip::ICMP_TYPE_TIME_EXCEED)
97 return "Time exceeded";
98 if (type == ip::ICMP_TYPE_BAD_IP_HDR)
99 return "IP header error";
106 : satcat5::net::Protocol(TYPE_ICMP)
108 , m_wait_msec(SATCAT5_ICMP_LOG_COOLDOWN)
113 #if SATCAT5_ALLOW_DELETION
114 ProtoIcmp::~ProtoIcmp()
129 u16 buff[ip::HDR_MAX_SHORTS + 8];
138 (*ptr++) = (u16)(arg >> 16);
139 (*ptr++) = (u16)(arg >> 0);
140 for (
unsigned a = 0 ; a < 2 * hdr.
ihl() ; ++a)
141 (*ptr++) = hdr.
data[a];
142 for (
unsigned a = 0 ; a < 4 ; ++a)
143 (*ptr++) = src->read_u16();
146 unsigned wcount = ptr - buff;
148 return write_icmp(wr, wcount, buff);
154 u32 now = SATCAT5_CLOCK->raw();
157 u16 buff[ECHO_WORDS];
158 buff[0] = ip::ICMP_ECHO_REQUEST;
160 buff[2] = (u16)(now >> 16);
161 buff[3] = (u16)(now >> 0);
165 return write_icmp(wr, ECHO_WORDS, buff);
171 u32 now = SATCAT5_CLOCK->raw() | TIMESTAMP_ARB;
174 u16 buff[TIME_WORDS];
175 buff[0] = ip::ICMP_TIME_REQUEST;
179 buff[4] = (u16)(now >> 16);
180 buff[5] = (u16)(now >> 0);
188 return write_icmp(wr, TIME_WORDS, buff);
195 static const unsigned MAX_REPLY = 32;
196 static const unsigned MAX_ECHO = MAX_REPLY - 2;
203 u16 code = src.read_u16();
208 u16 type = code & ip::ICMP_TYPE_MASK;
209 auto src_ip = m_iface->reply_ip();
210 if (code == ip::ICMP_ECHO_REPLY) {
217 item->
ping_event(m_iface->reply_ip(), elapsed);
218 item = m_listeners.
next(item);
220 }
else if (code == ip::ICMP_ECHO_REQUEST && wlen <= MAX_ECHO) {
222 buff[0] = ip::ICMP_ECHO_REPLY;
224 for (
unsigned a = 0 ; a < wlen ; ++a)
225 buff[a+2] = src.read_u16();
227 unsigned echo_len = wlen + 2;
229 write_icmp(wr, echo_len, buff);
230 }
else if (type == ip::ICMP_TYPE_REDIRECT && wlen >= 12) {
237 }
else if (code == ip::ICMP_TIME_REPLY && wlen >= 8) {
240 u32 stamp = src.read_u32();
242 }
else if (code == ip::ICMP_TIME_REQUEST && wlen >= 8) {
244 u32 now = SATCAT5_CLOCK->raw() | TIMESTAMP_ARB;
246 buff[0] = ip::ICMP_TIME_REPLY;
248 buff[2] = src.read_u16();
249 buff[3] = src.read_u16();
250 buff[4] = src.read_u16();
251 buff[5] = src.read_u16();
252 buff[6] = (u16)(now >> 16);
253 buff[7] = (u16)(now >> 0);
254 buff[8] = (u16)(now >> 16);
255 buff[9] = (u16)(now >> 0);
258 write_icmp(wr, TIME_WORDS, buff);
261 const char* msg = code2msg(code);
272 bool ProtoIcmp::write_icmp(
274 unsigned wcount, u16* data)
277 if (!wr)
return false;
280 data[1] = ip::checksum(wcount, data);
283 for (
unsigned a = 0 ; a < wcount ; ++a)
284 wr->write_u16(data[a]);
void gateway_change(const satcat5::ip::Addr &dstaddr, const satcat5::ip::Addr &gateway)
Notify all listeners of a change in gateway configuration.
Limited read of next N bytes.
bool read_consume(unsigned nbytes) override
Read and discard 0 or more bytes.
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Abstract API for reading byte-streams and packets.
bool read_obj(T &t)
Templated wrapper for any object with the following method: bool read_from(satcat5::io::Readable* rd)...
Abstract API for writing byte-streams and packets.
virtual bool write_finalize()
Mark end of frame and release temporary working data.
Connection metadata for an IPv4 address.
satcat5::io::Writeable * open_write(unsigned len) override
Open a new frame to the designated address and type.
Protocol handler and dispatch unit for Internet Protocol v4 (IPv4).
satcat5::io::Writeable * open_reply(const satcat5::net::Type &type, unsigned len) override
Get Writeable object for reply to the last received datagram.
Callback API for handling "ping" reponses.
virtual void ping_event(const satcat5::ip::Addr &from, u32 elapsed_usec)=0
Callback method when a ping response is received.
Protocol handler for the Internet Control Message Protocol (ICMP).
bool send_timereq(satcat5::ip::Address &dst)
Initiate a timestamp request.
void timer_event() override
Child class MUST override this method.
bool send_error(u16 type, satcat5::io::Readable *src, uint32_t arg=0)
Send a specific error message.
bool send_ping(satcat5::ip::Address &dst)
Initiate a ping (Echo request = Type 8.0).
void frame_rcvd(satcat5::io::LimitedRead &src) override
Dispatch calls frame_rcvd(...) for each incoming frame with with a matching net::Type value.
The Log class creates and formats one log message.
Log & write(const char *str)
Formatting methods for various data types.
void add(satcat5::net::Protocol *proto)
Register a Protocol object.
void remove(satcat5::net::Protocol *proto)
Unregister a Protocol object.
unsigned timer_remaining() const
Accessor for time to next event, if one is set.
void timer_once(unsigned msec)
Configure a one-time notification after X milliseconds.
T * next(const T *item) const
Fetch pointer to the next item.
Diagnostic logging to UART and/or Ethernet ports.
IPv4 address is a 32-bit unsigned integer.
Multipurpose filter for matching fields in network packets.
Timestamp for measuring elapsed time.
unsigned elapsed_usec() const
Elapsed time in microseconds.
TimeRef and TimeVal define the API for monotonic timers.