TEMU  3.0
The Terma Emulator
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 #define TEMU_ETH_PREAMBLE_LENGTH_MASK (0xf << 6)
71 #define TEMU_ETH_PREAMBLE_LENGTH_SHIFT 6
72 
73 typedef struct {
74  uint32_t Flags;
76  uint8_t Preamble[15];
77  uint8_t Sfd;
79 
85 TEMU_IFACE_REFERENCE_TYPE(temu_Ethernet);
86 
87 struct temu_MACIface {
88  void (*connected)(
89  void *Dev); // Called when link is connected (i.e. cable inserted)
90  void (*disconnected)(
91  void *Dev); // Called when link is disconnected (i.e. cable removed)
92  void (*up)(void *Dev); // Called when link goes up
93  void (*down)(void *Dev); // Called when link goes down
94 
95  int (*receive)(void *Dev, temu_EthFrame *Frame); // Receive frame
96  uint64_t (*getMAC)(void *Dev); // Get MAC address
97  void (*setMAC)(void *Dev, uint64_t MAC); // Set MAC address
98 };
99 #define TEMU_MAC_IFACE_TYPE "temu::MACIface"
100 
102  void (*connected)(
103  void *Dev,
104  temu_EthernetIfaceRef
105  Link); // Called when link is connected (i.e. cable inserted)
106  void (*disconnected)(
107  void *Dev,
108  temu_EthernetIfaceRef
109  Link); // Called when link is disconnected (i.e. cable removed), note
110  // that the PHY must remove the MACs from the link
111  void (*up)(void *Dev); // Called when link goes up
112  void (*down)(void *Dev); // Called when link goes down
113 
114  int (*send)(void *Dev, temu_EthFrame *Frame); // Send frame from MAC
115  int (*receive)(void *Dev, temu_EthFrame *Frame); // Receive frame
116 
117  // PHY should clear bits not related to its capabilities in the status and
118  // ext status registers
119  uint32_t (*autoNegotiate)(void *Obj, uint32_t Caps); // Do auto-negotiatio
120  void (*autoNegotiateDone)(void *Obj, uint32_t Caps);
121 };
122 #define TEMU_PHY_IFACE_TYPE "temu::PHYIface"
123 
124 // These bits should be transferred using auto-negotiation requests
125 // Matches MII status reg (reg 1), but needs to be shifted 8 bits up
126 #define TEMU_ETH_100BASE_T4 (1 << (15 - 8))
127 #define TEMU_ETH_100BASE_X_FD (1 << (14 - 8))
128 #define TEMU_ETH_100BASE_X_HD (1 << (13 - 8))
129 #define TEMU_ETH_10BASE_FD (1 << (12 - 8))
130 #define TEMU_ETH_10BASE_HD (1 << (11 - 8))
131 #define TEMU_ETH_100BASE_T2_FD (1 << (10 - 8))
132 #define TEMU_ETH_100BASE_T2_HD (1 << (9 - 8))
133 
134 // Matches MII extended status register (reg 15)
135 #define TEMU_ETH_1000BASE_X_FD (1 << 15)
136 #define TEMU_ETH_1000BASE_X_HD (1 << 14)
137 #define TEMU_ETH_1000BASE_T_FD (1 << 13)
138 #define TEMU_ETH_1000BASE_T_HD (1 << 12)
139 
140 // Interface for the actual link, a link can be a switch, hub, or a
141 // direct connection, note that ETH is not seen as a Point to Point
142 // connection for the reason of supporting HUBs, splitters etc.
144  void (*connect)(void *Obj,
145  temu_PHYIfaceRef Dev); // Called to connect a device
146  void (*disconnect)(void *Obj,
147  temu_PHYIfaceRef Dev); // Called to disconnect link
148 
149  // Ensure the device receives messages for this MAC address
150  // Note, do not forget to add broadcast and multicast bits
151  void (*addMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC);
152  void (*removeMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC);
153  void (*setPromiscuous)(void *Obj, temu_PHYIfaceRef Dev, int PromiscuousMode);
154 
155  // Do auto-negotiation, this results in queries on all attached devices
156  // that determines the shared link speed
157  uint32_t (*autoNegotiate)(void *Obj, uint32_t Caps);
158 
159  // Send frame to virtual ethernet cable return non zero if frame is
160  // accepted, link will route the frame to relevant devices
161  int (*send)(void *Obj, temu_EthFrame *Frame);
162 };
163 #define TEMU_ETHERNET_IFACE_TYPE "temu::EthernetIface"
164 
165 // I.e. Eth::connect() -> MAC::connected()
166 // I.e. Phy::send() -> Eth::receive()
167 
168 // MDIO interface
169 // The MDIO interface is for creating devices connected to an MDIO bus
170 // or to simulate an MDIO, note that we do not actually
171 // simulate MDIO per see, but do support mulpiple PHY controllers to
172 // be attached to the same bus.
173 typedef struct {
174  // The readReg returns negative if the call failed, it can fail if
175  // the access is to a bus and the PHY_ID is invalid or if the
176  // address is invalid. A successful means that the result can be
177  // safely be converted to a uint16_t.
178  int32_t (*readReg)(void *Obj, unsigned PHY_ID, uint16_t Addr);
179  int (*writeReg)(void *Obj, unsigned PHY_ID, uint16_t Addr, uint16_t Value);
181 #define TEMU_MDIO_IFACE_TYPE "temu::MDIOIface"
182 TEMU_IFACE_REFERENCE_TYPE(temu_MDIO);
183 
184 #define TEMU_ETH_MIN_PAYLOAD 46
185 #define TEMU_ETH_MAX_PAYLOAD 1500
186 #define TEMU_ETH_LAYER1_HEADER_LENGTH (7 + 1 + 12 + 2)
187 #define TEMU_ETH_LAYER2_HEADER_LENGTH (6 + 6 + 2)
188 #define TEMU_ETH_CRC_LENGTH 4
189 #define TEMU_ETH_INTERPACKET_GAP 12
190 #define TEMU_ETH_PAYLOAD_OFFSET (6 + 6 + 2)
191 #define TEMU_ETH_MAX_FRAME_LENGTH 1518
192 #define TEMU_ETH_802_1Q_TAG_BYTES 4
193 #define TEMU_ETH_802_1Q_MAX_FRAME_LENGTH 1522
194 
195 // An assortment of ethertype constants, non exhaustive.
196 // See: https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
197 // for a more complete list.
198 #define TEMU_ETHTYPE_IPV4 0x0800
199 #define TEMU_ETHTYPE_ARP 0x0806
200 #define TEMU_ETHTYPE_WAKE_ON_LAN 0x0842
201 #define TEMU_ETHTYPE_SRP 0x22ea
202 #define TEMU_ETHTYPE_RARP 0x8035
203 #define TEMU_ETHTYPE_802_1Q 0x8100
204 #define TEMU_ETHTYPE_IPV6 0x86dd
205 #define TEMU_ETHTYPE_PTP 0x88f7
206 #define TEMU_ETHTYPE_TTE_CTRL 0x891d
207 
208 // Note, this excludes 802.1Q field
209 #define TEMU_ETH_IPV4_VERS_IHL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 0)
210 #define TEMU_ETH_IPV4_DSCP_ECN_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 1)
211 #define TEMU_ETH_IPV4_TOTAL_LENGTH_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 2)
212 #define TEMU_ETH_IPV4_FRAGMENTATION_INFO_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 6)
213 #define TEMU_ETH_IPV4_TTL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 8)
214 #define TEMU_ETH_IPV4_PROTOCOL_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 9)
215 #define TEMU_ETH_IPV4_CRC_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 10)
216 #define TEMU_ETH_IPV4_SRC_IP_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 12)
217 #define TEMU_ETH_IPV4_DST_IP_OFFSET (TEMU_ETH_PAYLOAD_OFFSET + 16)
218 
219 #define TEMU_IP_PROT_TCP 0x06
220 #define TEMU_IP_PROT_UDP 0x11
221 
222 // Relative to start of TCP/UDP headers
223 #define TEMU_TCP_CRC_OFFSET 16
224 #define TEMU_UDP_CRC_OFFSET 6
225 
226 static inline uint64_t
227 temu_ethGetDestMAC(temu_EthFrame *Frame)
228 {
229  uint64_t MAC = 0;
230  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
231 
232  for (int i = 0; i < 6; ++i) {
233  MAC <<= 8;
234  MAC |= Data[i];
235  }
236  return MAC;
237 }
238 
239 static inline uint64_t
240 temu_ethGetSourceMAC(temu_EthFrame *Frame)
241 {
242  uint64_t MAC = 0;
243  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
244 
245  for (int i = 6; i < 12; ++i) {
246  MAC <<= 8;
247  MAC |= Data[i];
248  }
249  return MAC;
250 }
251 
257 static inline uint16_t
258 temu_ethGetEthTypeSizeField(temu_EthFrame *Frame)
259 {
260  uint16_t Size = 0;
261  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
262 
263  for (int i = 12; i < 14; ++i) {
264  Size <<= 8;
265  Size |= Data[i];
266  }
267 
268  if (Size == TEMU_ETHTYPE_802_1Q) {
269  Size = 0;
270  for (int i = 12 + TEMU_ETH_802_1Q_TAG_BYTES;
271  i < 14 + TEMU_ETH_802_1Q_TAG_BYTES; ++i) {
272  Size <<= 8;
273  Size |= Data[i];
274  }
275  }
276 
277  return Size;
278 }
279 
280 static inline bool
281 temu_ethIs8021Q(temu_EthFrame *Frame)
282 {
283  uint16_t TagStart = 0;
284  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
285 
286  for (int i = 12; i < 14; ++i) {
287  TagStart <<= 8;
288  TagStart |= Data[i];
289  }
290 
291  return TagStart == TEMU_ETHTYPE_802_1Q;
292 }
293 
294 static inline uint16_t
295 temu_eth8021QTagBytes(temu_EthFrame *Frame)
296 {
297  return temu_ethIs8021Q(Frame) ? TEMU_ETH_802_1Q_TAG_BYTES : 0;
298 }
299 
300 static inline uint16_t
301 temu_ethGetLength(temu_EthFrame *Frame)
302 {
303  // Should compute number of bits / bytes for the whole frame
304  // including headers
305  return temu_buffLen(&Frame->Data);
306 }
307 
313 static inline const uint8_t *
314 temu_ethGetPayload(temu_EthFrame *Frame)
315 {
316  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
317  return &Data[TEMU_ETH_PAYLOAD_OFFSET + temu_eth8021QTagBytes(Frame)];
318 }
319 
320 // Return actual payload size (including padding)
321 static inline const uint16_t
322 temu_ethGetPayloadAndPaddingSize(temu_EthFrame *Frame)
323 {
324  return temu_ethGetLength(Frame) - TEMU_ETH_PAYLOAD_OFFSET -
325  TEMU_ETH_CRC_LENGTH - temu_eth8021QTagBytes(Frame);
326 }
327 
328 #define ETH_BCAST_ADDR UINT64_C(0xffffffffffff)
329 
330 static inline int
331 temu_ethIsBroadcastFrame(temu_EthFrame *Frame)
332 {
333  uint64_t MAC = temu_ethGetDestMAC(Frame);
334  if (MAC == ETH_BCAST_ADDR) {
335  return 1;
336  }
337 
338  return 0;
339 }
340 
341 // Return 1 if frame is multicast (OR BROADCAST)
342 static inline int
343 temu_ethIsMulticastFrame(temu_EthFrame *Frame)
344 {
345  const uint8_t *Data = temu_buffReadableData(&Frame->Data);
346 
347  if (Data[0] & 1)
348  return 1;
349  return 0;
350 }
351 
352 // Len field specify ethertype if larger or equal to this value
353 #define ETH_ETHERTYPE_MIN 1536
354 
355 #define ETH_CRC_MAGIC 0xC704DD7B
356 #define ETH_CRC_POLY_NORM 0x04C11DB7
357 #define ETH_CRC_POLY_REV 0xEDB88320
358 #define ETH_CRC_POLY_REV_RECIP 0x82608EDB
359 
360 #define ETH_CRC_POLY_LE 0xedb88320
361 #define ETH_CRC_POLY_BE 0x04c11db6
362 
363 #ifdef __cplusplus
364 }
365 #endif
366 #endif /* !TEMU_ETHERNET_H */
int(* send)(void *Obj, temu_EthFrame *Frame)
Definition: Ethernet.h:161
void(* connected)(void *Dev, temu_EthernetIfaceRef Link)
Definition: Ethernet.h:102
#define TEMU_ETH_802_1Q_TAG_BYTES
Definition: Ethernet.h:192
void(* connected)(void *Dev)
Definition: Ethernet.h:88
TEMU_API uint32_t temu_buffLen(const temu_Buff *B)
uint32_t Flags
Flags used for error injection.
Definition: Ethernet.h:74
int(* send)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:114
#define TEMU_ETH_CRC_LENGTH
Definition: Ethernet.h:188
Definition: Ethernet.h:173
Definition: Ethernet.h:73
void(* disconnected)(void *Dev)
Definition: Ethernet.h:90
Definition: Ethernet.h:101
Definition: Ethernet.h:143
TEMU_IFACE_REFERENCE_TYPE(temu_MAC)
uint32_t(* autoNegotiate)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:119
void(* up)(void *Dev)
Definition: Ethernet.h:92
temu_Buff Data
ETH frame data.
Definition: Ethernet.h:75
uint8_t Sfd
Start frame delimiter, normally 0xab.
Definition: Ethernet.h:77
void(* removeMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC)
Definition: Ethernet.h:152
void(* autoNegotiateDone)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:120
TEMU_API const uint8_t * temu_buffReadableData(const temu_Buff *B)
void(* disconnected)(void *Dev, temu_EthernetIfaceRef Link)
Definition: Ethernet.h:106
void(* setMAC)(void *Dev, uint64_t MAC)
Definition: Ethernet.h:97
#define TEMU_ETHTYPE_802_1Q
Definition: Ethernet.h:203
int(* receive)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:115
uint64_t(* getMAC)(void *Dev)
Definition: Ethernet.h:96
void(* setPromiscuous)(void *Obj, temu_PHYIfaceRef Dev, int PromiscuousMode)
Definition: Ethernet.h:153
Definition: Ethernet.h:87
void(* down)(void *Dev)
Definition: Ethernet.h:112
void(* addMAC)(void *Obj, temu_PHYIfaceRef Dev, uint64_t MAC)
Definition: Ethernet.h:151
void(* up)(void *Dev)
Definition: Ethernet.h:111
int(* receive)(void *Dev, temu_EthFrame *Frame)
Definition: Ethernet.h:95
#define TEMU_ETH_PAYLOAD_OFFSET
Definition: Ethernet.h:190
#define ETH_BCAST_ADDR
Definition: Ethernet.h:328
void(* connect)(void *Obj, temu_PHYIfaceRef Dev)
Definition: Ethernet.h:144
void(* down)(void *Dev)
Definition: Ethernet.h:93
uint32_t(* autoNegotiate)(void *Obj, uint32_t Caps)
Definition: Ethernet.h:157
void(* disconnect)(void *Obj, temu_PHYIfaceRef Dev)
Definition: Ethernet.h:146
Definition: Buffer.h:83