TEMU  2
The Terma Emulator
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
Ethernet.h
Go to the documentation of this file.
1 //===------------------------------------------------------------*- C++ -*-===//
2 //
3 // TEMU: The Terma Emulator
4 // (c) Terma 2020
5 // Authors: Mattias Holm <maho (at) terma.com>
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef TEMU_ETHERNET_H
10 #define TEMU_ETHERNET_H
11 
13 #include "temu-c/Support/Buffer.h"
14 #include "temu-c/Support/Objsys.h"
15 
16 #include <stdint.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 /*
23  The ethernet device interface is EXPERIMENTAL and UNSTABLE at the
24  moment.
25 
26  MAC addresses are 6 bytes, as convention here, we encode these in a
27  uint64_t field, where the two MSBs are set to 0. The, MAC address
28  will be in host endianess.
29 
30  Ethernet simulation is based on the transmission of frames. Frames
31  do not need to have valid CRCs, but the CRC data bytes should be
32  allocated for the frames. This speeds up simulation significantly.
33 
34  CRC errors can instead be efficiently injected by flipping the
35  relevant bit in the flags field.
36 
37  Ethernet is not a point to point protocol (although in practice,
38  these days it is P2P thanks to switches which are collission free),
39  but we could immagine some one simulating an ethernet link via coax
40  in which case there may be multiple nodes connected to the same
41  cable. It is possible to tap the ethernet object by adding an
42  ethernet device to it that listens to all addresses (i.e. it
43  notifies the bus model about being "promiscuous").
44 
45  ETH support is split using multiple levels, i.e. a MAC and a PHY
46  controller. The PHY controller implements the PHY interface and
47  usually also the MII interface (there is a generic MII device that
48  can be used which implements both PHY and MII). PHY is used for
49  connecting to other PHY controllers, when sending a frame, the MAC
50  will (using e.g. DMA) get the frame data, assemble a temu_EthFrame
51  and send this to the PHY controller, the PHY controller in turn
52  forwards the frame to the destination PHY. In addition, there is an
53  MIIBus model which lets a single master control multiple PHY
54  devices. The MIIBus model implements the MII interface only and
55  simply routes the calls to the correct attached PHY device.
56 
57  So, the use is typically:
58 
59  MAC -> PHY -> ETH -> PHY -> MAC
60  */
61 
62 // Flag bits
63 #define TEMU_ETH_CRC_ERR 1
64 
65 #define TEMU_ETH_ETH_CRC_NOT_SET (1 << 1)
66 #define TEMU_ETH_IP_CRC_NOT_SET (1 << 2)
67 #define TEMU_ETH_UDP_CRC_NOT_SET (1 << 3)
68 #define TEMU_ETH_TCP_CRC_NOT_SET (1 << 4)
69 #define TEMU_ETH_NON_STANDARD_PREAMBLE (1 << 5)
70 
71 typedef struct {
72  uint32_t Flags;
74  uint8_t Preamble[7];
75  uint8_t Sfd;
77 
83 TEMU_IFACE_REFERENCE_TYPE(temu_Ethernet);
84 
85 struct temu_MACIface {
86  void (*connected)(
87  void *Dev); // Called when link is connected (i.e. cable inserted)
88  void (*disconnected)(
89  void *Dev); // Called when link is disconnected (i.e. cable removed)
90  void (*up)(void *Dev); // Called when link goes up
91  void (*down)(void *Dev); // Called when link goes down
92 
93  int (*receive)(void *Dev, temu_EthFrame *Frame); // Receive frame
94  uint64_t (*getMAC)(void *Dev); // Get MAC address
95  void (*setMAC)(void *Dev, uint64_t MAC); // Set MAC address
96 };
97 #define TEMU_MAC_IFACE_TYPE "temu::MACIface"
98 
99 struct temu_PHYIface {
100  void (*connected)(
101  void *Dev,
102  temu_EthernetIfaceRef
103  Link); // Called when link is connected (i.e. cable inserted)
104  void (*disconnected)(
105  void *Dev,
106  temu_EthernetIfaceRef
107  Link); // Called when link is disconnected (i.e. cable removed), note
108  // that the PHY must remove the MACs from the link
109  void (*up)(void *Dev); // Called when link goes up
110  void (*down)(void *Dev); // Called when link goes down
111 
112  int (*send)(void *Dev, temu_EthFrame *Frame); // Send frame from MAC
113  int (*receive)(void *Dev, temu_EthFrame *Frame); // Receive frame
114 
115  // PHY should clear bits not related to its capabilities in the status and
116  // ext status registers
117  uint32_t (*autoNegotiate)(void *Obj, uint32_t Caps); // Do auto-negotiatio
118  void (*autoNegotiateDone)(void *Obj, uint32_t Caps);
119 };
120 #define TEMU_PHY_IFACE_TYPE "temu::PHYIface"
121 
122 // These bits should be transferred using auto-negotiation requests
123 // Matches MII status reg (reg 1), but needs to be shifted 8 bits up
124 #define TEMU_ETH_100BASE_T4 (1 << (15 - 8))
125 #define TEMU_ETH_100BASE_X_FD (1 << (14 - 8))
126 #define TEMU_ETH_100BASE_X_HD (1 << (13 - 8))
127 #define TEMU_ETH_10BASE_FD (1 << (12 - 8))
128 #define TEMU_ETH_10BASE_HD (1 << (11 - 8))
129 #define TEMU_ETH_100BASE_T2_FD (1 << (10 - 8))
130 #define TEMU_ETH_100BASE_T2_HD (1 << (9 - 8))
131 
132 // Matches MII extended status register (reg 15)
133 #define TEMU_ETH_1000BASE_X_FD (1 << 15)
134 #define TEMU_ETH_1000BASE_X_HD (1 << 14)
135 #define TEMU_ETH_1000BASE_T_FD (1 << 13)
136 #define TEMU_ETH_1000BASE_T_HD (1 << 12)
137 
138 // Interface for the actual link, a link can be a switch, hub, or a
139 // direct connection, note that ETH is not seen as a Point to Point
140 // connection for the reason of supporting HUBs, splitters etc.
142  void (*connect)(void *Obj,
143  temu_PHYIfaceRef Dev); // Called to connect a device
144  void (*disconnect)(void *Obj,
145  temu_PHYIfaceRef Dev); // Called to disconnect link
146 
147  // Ensure the device receives messages for this MAC address
148  // Note, do not forget to add broadcast and multicast bits
149  void (*addMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC);
150  void (*removeMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC);
151  void (*setPromiscuous)(void *Obj, temu_PHYIfaceRef Dev, int PromiscuousMode);
152 
153  // Do auto-negotiation, this results in queries on all attached devices
154  // that determines the shared link speed
155  uint32_t (*autoNegotiate)(void *Obj, uint32_t Caps);
156 
157  // Send frame to virtual ethernet cable return non zero if frame is
158  // accepted, link will route the frame to relevant devices
159  int (*send)(void *Obj, temu_EthFrame *Frame);
160 };
161 #define TEMU_ETHERNET_IFACE_TYPE "temu::EthernetIface"
162 
163 // I.e. Eth::connect() -> MAC::connected()
164 // I.e. Phy::send() -> Eth::receive()
165 
166 // MDIO interface
167 // The MDIO interface is for creating devices connected to an MDIO bus
168 // or to simulate an MDIO, note that we do not actually
169 // simulate MDIO per see, but do support mulpiple PHY controllers to
170 // be attached to the same bus.
171 typedef struct {
172  // The readReg returns negative if the call failed, it can fail if
173  // the access is to a bus and the PHY_ID is invalid or if the
174  // address is invalid. A successful means that the result can be
175  // safely be converted to a uint16_t.
176  int32_t (*readReg)(void *Obj, unsigned PHY_ID, uint16_t Addr);
177  int (*writeReg)(void *Obj, unsigned PHY_ID, uint16_t Addr, uint16_t Value);
179 #define TEMU_MDIO_IFACE_TYPE "temu::MDIOIface"
180 TEMU_IFACE_REFERENCE_TYPE(temu_MDIO);
181 
182 #define TEMU_ETH_MIN_PAYLOAD 46
183 #define TEMU_ETH_MAX_PAYLOAD 1500
184 #define TEMU_ETH_LAYER1_HEADER_LENGTH (7 + 1 + 12 + 2)
185 #define TEMU_ETH_LAYER2_HEADER_LENGTH (6 + 6 + 2)
186 #define TEMU_ETH_CRC_LENGTH 4
187 #define TEMU_ETH_INTERPACKET_GAP 12
188 #define TEMU_ETH_PAYLOAD_OFFSET (6 + 6 + 2)
189 #define TEMU_ETH_MAX_FRAME_LENGTH 1518
190 #define TEMU_ETH_802_1Q_MAX_FRAME_LENGTH 1522
191 
192 // An assortment of ethertype constants, non exhaustive.
193 // See: https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
194 // for a more complete list.
195 #define TEMU_ETHTYPE_IPV4 0x0800
196 #define TEMU_ETHTYPE_ARP 0x0806
197 #define TEMU_ETHTYPE_WAKE_ON_LAN 0x0842
198 #define TEMU_ETHTYPE_SRP 0x22ea
199 #define TEMU_ETHTYPE_RARP 0x8035
200 #define TEMU_ETHTYPE_802_1Q 0x8100
201 #define TEMU_ETHTYPE_IPV6 0x86dd
202 #define TEMU_ETHTYPE_PTP 0x88f7
203 #define TEMU_ETHTYPE_TTE_CTRL 0x891d
204 
205 // Note, this excludes 802.1Q field
206 #define TEMU_ETH_IPV4_VERS_IHL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 0)
207 #define TEMU_ETH_IPV4_DSCP_ECN_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 1)
208 #define TEMU_ETH_IPV4_TOTAL_LENGTH_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 2)
209 #define TEMU_ETH_IPV4_FRAGMENTATION_INFO_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 6)
210 #define TEMU_ETH_IPV4_TTL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 8)
211 #define TEMU_ETH_IPV4_PROTOCOL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 9)
212 #define TEMU_ETH_IPV4_CRC_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 10)
213 #define TEMU_ETH_IPV4_SRC_IP_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 12)
214 #define TEMU_ETH_IPV4_DST_IP_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 16)
215 
216 #define TEMU_IP_PROT_TCP 0x06
217 #define TEMU_IP_PROT_UDP 0x11
218 
219 // Relative to start of TCP/UDP headers
220 #define TEMU_TCP_CRC_OFFSET 16
221 #define TEMU_UDP_CRC_OFFSET 6
222 
223 static inline uint64_t
224 temu_ethGetDestMAC(temu_EthFrame *Frame)
225 {
226  uint64_t MAC = 0;
227  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
228 
229  for (int i = 0; i < 6; ++i) {
230  MAC <<= 8;
231  MAC |= Data[i];
232  }
233  return MAC;
234 }
235 
236 static inline uint64_t
237 temu_ethGetSourceMAC(temu_EthFrame *Frame)
238 {
239  uint64_t MAC = 0;
240  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
241 
242  for (int i = 6; i < 12; ++i) {
243  MAC <<= 8;
244  MAC |= Data[i];
245  }
246  return MAC;
247 }
248 
249 static inline uint16_t
250 temu_ethGetLength(temu_EthFrame *Frame)
251 {
252  // Should compute number of bits / bytes for the whole frame
253  // including headers
254  return temu_buffLen(&Frame->Data);
255 }
256 
262 static inline const uint8_t *
263 temu_ethGetPayload(temu_EthFrame *Frame)
264 {
265  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
266  return &Data[TEMU_ETH_PAYLOAD_OFFSET];
267 }
268 
269 // Return actual payload size (including padding)
270 static inline const uint16_t
271 temu_ethGetPayloadAndPaddingSize(temu_EthFrame *Frame)
272 {
273  return temu_ethGetLength(Frame) - TEMU_ETH_PAYLOAD_OFFSET -
275 }
276 
282 static inline uint16_t
283 temu_ethGetEthTypeSizeField(temu_EthFrame *Frame)
284 {
285  uint16_t Size = 0;
286  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
287 
288  for (int i = 12; i < 14; ++i) {
289  Size <<= 8;
290  Size |= Data[i];
291  }
292  return Size;
293 }
294 
295 #define ETH_BCAST_ADDR UINT64_C(0xffffffffffff)
296 
297 static inline int
298 temu_ethIsBroadcastFrame(temu_EthFrame *Frame)
299 {
300  uint64_t MAC = temu_ethGetDestMAC(Frame);
301  if (MAC == ETH_BCAST_ADDR) {
302  return 1;
303  }
304 
305  return 0;
306 }
307 
308 // Return 1 if frame is multicast (OR BROADCAST)
309 static inline int
310 temu_ethIsMulticastFrame(temu_EthFrame *Frame)
311 {
312  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
313 
314  if (Data[0] & 1)
315  return 1;
316  return 0;
317 }
318 
319 // Len field specify ethertype if larger or equal to this value
320 #define ETH_ETHERTYPE_MIN 1536
321 
322 #define ETH_CRC_MAGIC 0xC704DD7B
323 #define ETH_CRC_POLY_NORM 0x04C11DB7
324 #define ETH_CRC_POLY_REV 0xEDB88320
325 #define ETH_CRC_POLY_REV_RECIP 0x82608EDB
326 
327 #define ETH_CRC_POLY_LE 0xedb88320
328 #define ETH_CRC_POLY_BE 0x04c11db6
329 
330 #ifdef __cplusplus
331 }
332 #endif
333 #endif /* !TEMU_ETHERNET_H */
#define TEMU_ETH_PAYLOAD_OFFSET
Definition: Ethernet.h:188
uint8_t Sfd
Start frame delimiter, normally 0xab.
Definition: Ethernet.h:75
void(* disconnected)(void *Dev)
Definition: Ethernet.h:88
TEMU_API const uint8_t * temu_buffReadableData(const temu_Buff *B)
void(* down)(void *Dev)
Definition: Ethernet.h:91
int(* send)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:112
void(* down)(void *Dev)
Definition: Ethernet.h:110
void(* removeMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC)
Definition: Ethernet.h:150
void(* disconnected)(void *Dev, temu_EthernetIfaceRef Link)
Definition: Ethernet.h:104
void(* setMAC)(void *Dev, uint64_t MAC)
Definition: Ethernet.h:95
int(* receive)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:93
void(* autoNegotiateDone)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:118
uint32_t Flags
Flags used for error injection.
Definition: Ethernet.h:72
void(* addMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC)
Definition: Ethernet.h:149
#define ETH_BCAST_ADDR
Definition: Ethernet.h:295
uint64_t(* getMAC)(void *Dev)
Definition: Ethernet.h:94
void(* disconnect)(void *Obj, temu_PHYIfaceRef Dev)
Definition: Ethernet.h:144
int(* receive)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:113
#define TEMU_IFACE_REFERENCE_TYPE(N)
Definition: Objsys.h:129
void(* connected)(void *Dev, temu_EthernetIfaceRef Link)
Definition: Ethernet.h:100
void(* connected)(void *Dev)
Definition: Ethernet.h:86
TEMU_API uint32_t temu_buffLen(const temu_Buff *B)
#define TEMU_ETH_CRC_LENGTH
Definition: Ethernet.h:186
uint32_t(* autoNegotiate)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:155
int(* send)(void *Obj, temu_EthFrame *Frame)
Definition: Ethernet.h:159
void(* connect)(void *Obj, temu_PHYIfaceRef Dev)
Definition: Ethernet.h:142
void(* up)(void *Dev)
Definition: Ethernet.h:90
void(* setPromiscuous)(void *Obj, temu_PHYIfaceRef Dev, int PromiscuousMode)
Definition: Ethernet.h:151
temu_Buff Data
ETH frame data.
Definition: Ethernet.h:73
uint32_t(* autoNegotiate)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:117
void(* up)(void *Dev)
Definition: Ethernet.h:109