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