SatCat5
eth_dispatch.cc
1 // Copyright 2021-2024 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/eth_dispatch.h>
7 #include <satcat5/io_core.h>
8 #include <satcat5/log.h>
9 #include <satcat5/timeref.h>
10 
11 namespace eth = satcat5::eth;
13 using satcat5::net::Type;
14 
15 // Set verbosity level (0/1/2)
16 static const unsigned DEBUG_VERBOSE = 0;
17 
18 // Baseline Ethernet header is 14 bytes (dst + src + type).
19 // IEEE 802.1q VLAN tags add another four bytes.
20 constexpr unsigned ETH_HEADER_BYTES = SATCAT5_VLAN_ENABLE ? 18 : 14;
21 
23  const eth::MacAddr& addr,
26  : m_addr(addr) // MAC address for this endpoint
27  , m_dst(dst) // Destination pipe (Writeable)
28  , m_src(src) // Source pipe (Readable)
29  , m_reply_dstaddr(eth::MACADDR_NONE)
30  , m_reply_srcaddr(eth::MACADDR_NONE)
31  , m_reply_type(eth::ETYPE_NONE)
32  , m_reply_vtag(eth::VTAG_NONE)
33  , m_default_vid(eth::VTAG_NONE)
34 {
35  m_src->set_callback(this);
36 }
37 
38 #if SATCAT5_ALLOW_DELETION
39 Dispatch::~Dispatch()
40 {
41  if (m_src) m_src->set_callback(0);
42 }
43 #endif
44 
46 {
47  eth::MacType etype;
48  eth::VlanTag vtag;
49 
50  if (DEBUG_VERBOSE > 1) {
51  if (SATCAT5_VLAN_ENABLE) {
52  log::Log(log::DEBUG, "EthDispatch: open_reply").write(type.as_u32());
53  } else {
54  log::Log(log::DEBUG, "EthDispatch: open_reply").write(type.as_u16());
55  }
56  }
57 
58  // Abort if there's not enough space for the entire frame.
59  if (m_dst->get_write_space() < ETH_HEADER_BYTES + len) return 0;
60 
61  if (SATCAT5_VLAN_ENABLE) {
62  // VLAN support: Pull EtherType and VLAN tag from "type" parameter.
63  type.as_pair(vtag.value, etype.value);
64  // Use specified VID if present; otherwise use the stored reply VID.
65  if (vtag.vid() == 0) vtag.value |= m_reply_vtag.value;
66  return open_write(m_reply_srcaddr, etype, vtag);
67  } else {
68  // No VLAN support, EtherType is the only parameter.
69  type.as_u16(etype.value);
70  return open_write(m_reply_srcaddr, etype);
71  }
72 }
73 
75  const eth::MacAddr& dst,
76  const eth::MacType& type,
77  eth::VlanTag vtag)
78 {
79  if (DEBUG_VERBOSE > 0)
80  log::Log(log::DEBUG, "EthDispatch: open_write").write(type.value);
81 
82  // Sanity check: Valid destination?
83  if (dst == satcat5::eth::MACADDR_NONE) return 0;
84 
85  // Sanity check: Valid EtherType?
86  // (Transmission of ye olde style frame length is not supported.)
87  if (type.value < 1536) return 0;
88 
89  // Sanity check: Is there room for the frame header?
90  // If not, wait a few microseconds and try again before giving up.
91  // (Workaround for edge-case where MailMap block is still busy.)
92  if (m_dst->get_write_space() < ETH_HEADER_BYTES) {
93  SATCAT5_CLOCK->busywait_usec(20);
94  if (m_dst->get_write_space() < ETH_HEADER_BYTES) return 0;
95  }
96 
97  // Override outgoing VID, if none is specified.
98  // (Useful for ports where VLAN tags are mandatory.)
99  if (vtag.vid() == 0) vtag.value |= m_default_vid.value;
100 
101  // Write out the Ethernet frame header:
102  m_dst->write_obj(dst); // Destination
103  m_dst->write_obj(m_addr); // Source
104  if (SATCAT5_VLAN_ENABLE && vtag.value) {
105  m_dst->write_obj(satcat5::eth::ETYPE_VTAG);
106  m_dst->write_obj(vtag); // VLAN tag (optional)
107  }
108  m_dst->write_obj(type); // EtherType
109 
110  // Ready to start writing frame contents.
111  return m_dst;
112 }
113 
115 {
116  m_addr = macaddr;
117 }
118 
120 {
121  // Attempt to read the Ethernet frame header.
122  eth::Header hdr;
123  bool pending = m_src->read_obj(hdr);
124 
125  if (DEBUG_VERBOSE > 0)
126  log::Log(log::DEBUG, "EthDispatch: data_rcvd ").write(pending ? "OK" : "Error");
127 
128  // Store reply address.
129  m_reply_dstaddr = hdr.dst;
130  m_reply_srcaddr = hdr.src;
131  m_reply_type = hdr.type;
132 
133  // Attempt delivery using specific VLAN tag, if applicable (VID > 0)
134  // (This allows VLAN-specific handlers to take priority over generic ones.)
135  #if SATCAT5_VLAN_ENABLE
136  m_reply_vtag.value = hdr.vtag.vid(); // Store VID field only (LSBs)
137  if (pending && hdr.vtag.vid()) {
138  Type typ_vlan(hdr.vtag.vid(), hdr.type.value);
139  pending = !deliver(typ_vlan, m_src, m_src->get_read_ready());
140  }
141  #endif
142 
143  // Attempt delivery using EtherType only (basic service or catch-all).
144  // (This allows generic handlers to catch tagged packets AND allows
145  // untagged packets to match the VLAN-specific handlers.)
146  if (pending) {
147  Type typ_basic(hdr.type.value);
148  pending = !deliver(typ_basic, m_src, m_src->get_read_ready());
149  }
150 
151  // If we reach this point, all delivery attempts failed.
152  if (pending && DEBUG_VERBOSE > 1)
153  log::Log(log::DEBUG, "EthDispatch: Unsupported EtherType").write(hdr.type.value);
154 
155  // Clean-up rest of packet, if applicable.
156  m_src->read_finalize();
157 }
158 
159 void Dispatch::data_unlink(satcat5::io::Readable* src) {m_src = 0;} // GCOVR_EXCL_LINE
Implemention of "net::Dispatch" for Ethernet frames.
Definition: eth_dispatch.h:21
void data_rcvd(satcat5::io::Readable *src) override
The data_rcvd() callback is polled whenever data is available.
void set_macaddr(const satcat5::eth::MacAddr &macaddr)
Set the local MAC-address.
void data_unlink(satcat5::io::Readable *src) override
Unlink this EventListener from the designated source, because the designated Readable object is being...
satcat5::io::Writeable * open_reply(const satcat5::net::Type &type, unsigned len) override
Send a reply to the most recent received frame.
Definition: eth_dispatch.cc:45
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
Abstract API for reading byte-streams and packets.
Definition: io_readable.h:68
bool read_obj(T &t)
Templated wrapper for any object with the following method: bool read_from(satcat5::io::Readable* rd)...
Definition: io_readable.h:140
virtual void read_finalize()
Consume any remaining bytes in this frame, if applicable.
Definition: io_readable.cc:270
virtual void set_callback(satcat5::io::EventListener *callback)
Update registered callback for data_rcvd() events.
Definition: io_readable.cc:39
virtual unsigned get_read_ready() const =0
How many bytes can be read without blocking?
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
virtual unsigned get_write_space() const =0
How many bytes can be written without blocking?
void write_obj(const T &obj)
Templated wrapper for any object with the following method: void write_to(satcat5::io::Writeable* wr)...
Definition: io_writeable.h:104
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
Dispatch()
Constructor and destructor access restricted to children.
Definition: net_dispatch.h:68
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
I/O interface core definitions.
Diagnostic logging to UART and/or Ethernet ports.
An Ethernet frame header.
Definition: eth_header.h:167
satcat5::eth::MacType type
Ethernet header fields.
Definition: eth_header.h:172
satcat5::eth::VlanTag vtag
Ethernet header fields.
Definition: eth_header.h:173
satcat5::eth::MacAddr src
Ethernet header fields.
Definition: eth_header.h:171
satcat5::eth::MacAddr dst
Ethernet header fields.
Definition: eth_header.h:170
An Ethernet MAC address (with serializable interface).
Definition: eth_header.h:29
EtherType field (uint16) is used a protocol-ID [1536..65535].
Definition: eth_header.h:96
u16 value
The 16-bit value is stored in processor-native order.
Definition: eth_header.h:98
Header contents for an 802.1Q Virtual-LAN tag.
Definition: eth_header.h:124
u16 value
The 16-bit value holds VID, DEI, and PCP fields.
Definition: eth_header.h:126
u16 vid() const
Accessors for each individual field.
Definition: eth_header.h:135
Multipurpose filter for matching fields in network packets.
Definition: net_type.h:38
u16 as_u16() const
Accessors for m_value.
Definition: net_type.h:65
void as_pair(u16 &a, u16 &b) const
Sets the given parameter to m_value.
Definition: net_type.h:74
u32 as_u32() const
Accessors for m_value.
Definition: net_type.h:66
TimeRef and TimeVal define the API for monotonic timers.