SatCat5
ip_dispatch.cc
1 // Copyright 2021-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_dispatch.h>
7 #include <satcat5/log.h>
8 #include <satcat5/timeref.h>
9 
10 using satcat5::eth::ETYPE_IPV4;
14 using satcat5::net::Type;
15 namespace ip = satcat5::ip;
16 namespace log = satcat5::log;
17 
18 // Set verbosity level (0/1/2)
19 static const unsigned DEBUG_VERBOSE = 0;
20 
21 Dispatch::Dispatch(
22  const ip::Addr& addr,
24  satcat5::ip::Table* route)
25  : Protocol(Type(ETYPE_IPV4.value))
26  , m_iface(iface)
27  , m_route(route)
28  , m_addr(addr)
29  , m_arp(iface, addr)
30  , m_icmp(this)
31  , m_igmp(this)
32  , m_reply_dst(ip::ADDR_NONE)
33  , m_reply_src(ip::ADDR_NONE)
34  , m_ident(0)
35 {
36  m_arp.add(this);
37  m_iface->add(this);
38 
39  // For historical reasons, this class seeds the global PRNG.
40  satcat5::util::prng.seed(SATCAT5_CLOCK->raw());
41  m_ident = u16(satcat5::util::prng.next());
42 }
43 
44 #if SATCAT5_ALLOW_DELETION
45 Dispatch::~Dispatch() {
46  m_arp.remove(this);
47  m_iface->remove(this);
48 }
49 #endif
50 
51 satcat5::io::Writeable* Dispatch::open_reply(const Type& type, unsigned len) {
52  return open_write(m_iface->reply_mac(), m_iface->reply_vtag(), m_reply_src, type.as_u8(), len);
53 }
54 
56  const satcat5::eth::MacAddr& mac, // Destination MAC
57  const satcat5::eth::VlanTag& vtag, // VLAN information
58  const ip::Addr& dst, // Destination IP
59  u8 protocol, // Protocol (UDP/TCP/etc)
60  unsigned len) // Length after IP header
61 {
62  if (DEBUG_VERBOSE > 1)
63  log::Log(log::DEBUG, "IpDispatch: open_write");
64 
65  // Write the Ethernet frame header.
66  satcat5::io::Writeable* wr = m_iface->open_write(mac, ETYPE_IPV4, vtag);
67  if (!wr) return 0; // Unable to proceed?
68 
69  // Write the IPv4 header before handing off to user.
70  next_header(protocol, dst, len).write_to(wr);
71  return wr; // Ready for packet contents.
72 }
73 
74 void Dispatch::set_addr(const ip::Addr& addr) {
75  m_addr = addr;
76  m_arp.set_ipaddr(addr);
77 }
78 
80  u8 protocol, const ip::Addr& dst, unsigned inner_bytes, u8 ttl)
81 {
82  // TTL + protocol word puts TTL in MSBs.
83  u16 ttl_word = 256 * u16(ttl) + protocol;
84  u16 len_total = (u16)(inner_bytes + ip::HDR_MIN_BYTES);
85 
86  // Populate header fields so we can calculate checksum.
87  Header hdr;
88  hdr.data[0] = 0x4500; // Version (4) + IHL (5 wds) + No DSCP/ECN
89  hdr.data[1] = len_total; // Total packet length (incl header)
90  hdr.data[2] = m_ident++; // Identification = sequential counter
91  hdr.data[3] = 0; // No fragmentation when sending
92  hdr.data[4] = ttl_word; // TTL + Protocol (see above)
93  hdr.data[5] = 0; // Placeholder for checksum
94  hdr.data[6] = (u16)(m_addr.value >> 16); // Source IP (MSW then LSW)
95  hdr.data[7] = (u16)(m_addr.value >> 0);
96  hdr.data[8] = (u16)(dst.value >> 16); // Destination IP (MSW then LSW)
97  hdr.data[9] = (u16)(dst.value >> 0);
98  return hdr;
99 }
100 
101 void Dispatch::arp_event(const MacAddr& mac, const ip::Addr& ip) {
102  // Cache this MAC address in the routing table.
103  route_cache(ip, mac);
104 }
105 
107  if (DEBUG_VERBOSE > 1)
108  log::Log(log::DEBUG, "IpDispatch: frame_rcvd").write((u16)rd.get_read_ready());
109 
110  // Attempt to read IPv4 header...
111  bool ok = m_reply_hdr.read_from(&rd);
112  if (ok && DEBUG_VERBOSE > 1) {
113  log::Log(log::DEBUG, "IpDispatch: Header OK");
114  } else if (!ok && DEBUG_VERBOSE > 0) {
115  log::Log(log::INFO, "IpDispatch: Header error").write(m_reply_hdr.chk());
116  }
117  if (!ok) return;
118 
119  // Ignore fragmented packets (not supported).
120  if (m_reply_hdr.frg()) return;
121 
122  // Note source and destination address.
123  m_reply_dst = m_reply_hdr.dst();
124  m_reply_src = m_reply_hdr.src();
125 
126  // Check destination. Is this packet intended for us?
127  bool accept = (m_reply_dst == m_addr) // Regular unicast
128  || (m_reply_dst.is_multicast()) // Broadcast or multicast
129  || (m_addr == ip::ADDR_NONE); // Local address not (yet) set
130  if (!accept) return;
131 
132  // Deliver packet to the appropriate handler (ICMP/UDP/TCP/etc.)
133  auto typ = Type(m_reply_hdr.proto());
134  auto len = m_reply_hdr.len_inner();
135  ok = deliver(typ, &rd, len);
136 
137  // Send an ICMP "Protocol unreachable" error?
138  if (!ok && !m_reply_dst.is_multicast())
139  m_icmp.send_error(ICMP_UNREACHABLE_PROTO, &rd);
140 }
Implemention of "net::Dispatch" for Ethernet frames.
Definition: eth_dispatch.h:21
satcat5::io::Writeable * open_write(const satcat5::eth::MacAddr &dst, const satcat5::eth::MacType &type, satcat5::eth::VlanTag vtag=satcat5::eth::VTAG_NONE)
Send a frame to the designated Ethernet address/VLAN.
Definition: eth_dispatch.cc:74
void set_ipaddr(const satcat5::ip::Addr &ipaddr)
Set the local IP address.
Definition: eth_arp.h:83
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
Limited read of next N bytes.
Definition: io_readable.h:255
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Definition: io_readable.cc:293
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
Protocol handler and dispatch unit for Internet Protocol v4 (IPv4).
Definition: ip_dispatch.h:43
bool route_cache(const satcat5::ip::Addr &gateway, const satcat5::eth::MacAddr &dstmac)
Routing table shortcuts.
Definition: ip_dispatch.h:85
satcat5::io::Writeable * open_write(const satcat5::eth::MacAddr &mac, const satcat5::eth::VlanTag &vtag, const satcat5::ip::Addr &ip, u8 protocol, unsigned len)
Get Writeable object for sending to a specific IP/MAC address.
Definition: ip_dispatch.cc:55
void frame_rcvd(satcat5::io::LimitedRead &src) override
Dispatch calls frame_rcvd(...) for each incoming frame with with a matching net::Type value.
Definition: ip_dispatch.cc:106
satcat5::io::Writeable * open_reply(const satcat5::net::Type &type, unsigned len) override
Get Writeable object for reply to the last received datagram.
Definition: ip_dispatch.cc:51
void arp_event(const satcat5::eth::MacAddr &mac, const satcat5::ip::Addr &ip) override
Callback for any announced MAC/IP address pair.
Definition: ip_dispatch.cc:101
void set_addr(const satcat5::ip::Addr &addr)
Set the local IP-address.
Definition: ip_dispatch.cc:74
satcat5::ip::Header next_header(u8 protocol, const satcat5::ip::Addr &dst, unsigned inner_bytes, u8 ttl=SATCAT5_IP_TTL)
Create a basic IPv4 header with the specified information.
Definition: ip_dispatch.cc:79
bool send_error(u16 type, satcat5::io::Readable *src, uint32_t arg=0)
Send a specific error message.
Definition: ip_icmp.cc:120
IPv4 forwarding table.
Definition: ip_table.h:144
The Log class creates and formats one log message.
Definition: log.h:195
Log & write(const char *str)
Formatting methods for various data types.
Definition: log.cc:198
void add(satcat5::net::Protocol *proto)
Register a Protocol object.
Definition: net_dispatch.h:55
bool deliver(const satcat5::net::Type &type, satcat5::io::Readable *src, unsigned len)
Deliver current message by calling Protocol::frame_rcvd(...).
Definition: net_dispatch.cc:25
void remove(satcat5::net::Protocol *proto)
Unregister a Protocol object.
Definition: net_dispatch.h:59
void seed(u64 seed)
Reset to the provided PRNG state.
Definition: utils.h:378
Diagnostic logging to UART and/or Ethernet ports.
An Ethernet MAC address (with serializable interface).
Definition: eth_header.h:29
Header contents for an 802.1Q Virtual-LAN tag.
Definition: eth_header.h:124
IPv4 address is a 32-bit unsigned integer.
Definition: ip_core.h:15
u32 value
Raw access to the underlying representation.
Definition: ip_core.h:17
bool is_multicast() const
IP multicast (224.*.*.*)
Definition: ip_core.cc:41
Structure for holding an IPv4 Header, including options.
Definition: ip_core.h:180
void write_to(satcat5::io::Writeable *wr) const
Write IPv4 header to the designated stream.
Definition: ip_core.cc:82
constexpr unsigned len_inner() const
< Inner bytes excluding header
Definition: ip_core.h:200
constexpr u16 chk() const
< Checksum (incoming only)
Definition: ip_core.h:206
bool read_from(satcat5::io::Readable *rd)
Read an entire IPv4 header from the designated stream.
Definition: ip_core.cc:127
constexpr u8 proto() const
< Inner protocol (UDP/TCP/etc.)
Definition: ip_core.h:204
constexpr u16 frg() const
< Fragment offset
Definition: ip_core.h:198
constexpr satcat5::ip::Addr dst() const
< Destination address
Definition: ip_core.h:210
u16 data[HDR_MAX_SHORTS]
Raw access to the underlying header contents.
Definition: ip_core.h:182
constexpr satcat5::ip::Addr src() const
< Source address
Definition: ip_core.h:208
Multipurpose filter for matching fields in network packets.
Definition: net_type.h:38
u8 as_u8() const
Accessors for m_value.
Definition: net_type.h:64
TimeRef and TimeVal define the API for monotonic timers.