scc 2026.07
SystemC components library
eth_tlm.cpp
1#include "eth_tlm.h"
2namespace eth {
3ethernet_frame ethernet_frame::parse_ethernet(nonstd::span<const std::uint8_t> frame) {
4 ethernet_frame eth_frame{};
5
6 if(frame.size() < sizeof(ethernet_header))
7 throw std::runtime_error("frame too small for Ethernet header");
8
9 // Copy header safely (no unaligned access)
10 std::memcpy(&eth_frame.l2, frame.data(), sizeof(ethernet_header));
11 std::uint16_t t = bswap16(eth_frame.l2.type_or_len);
12
13 std::size_t offset = sizeof(ethernet_header);
14
15 // VLAN TPIDs commonly: 0x8100 (802.1Q), 0x88A8 (802.1ad/QinQ)
16 auto is_vlan_tpid = [](std::uint16_t x) { return x == 0x8100 || x == 0x88A8; };
17
18 if(is_vlan_tpid(t)) {
19 if(frame.size() < offset + sizeof(vlan_tag_8021Q) + 2)
20 throw std::runtime_error("frame too small for VLAN tag");
21
22 vlan_tag_8021Q tag{};
23 std::memcpy(&tag, frame.data() + offset, sizeof(tag));
24 eth_frame.has_vlan = true;
25 eth_frame.vlan_tpid = t;
26
27 std::uint16_t tci = bswap16(tag.tci);
28 eth_frame.vlan_pcp = (tci >> 13) & 0x7;
29 eth_frame.vlan_dei = ((tci >> 12) & 0x1) != 0;
30 eth_frame.vlan_id = tci & 0x0FFF;
31
32 offset += sizeof(vlan_tag_8021Q);
33
34 // Next 2 bytes after VLAN tag is the *real* EtherType/Len
35 std::uint16_t inner{};
36 std::memcpy(&inner, frame.data() + offset, sizeof(inner));
37 t = bswap16(inner);
38 offset += sizeof(inner);
39 }
40
41 // Distinguish Ethernet II EtherType vs 802.3 length:
42 // <=1500 => length, >=1536 (0x0600) => EtherType
43 if(t <= 1500) {
44 eth_frame.kind = ether_kind::LENGTH_8023;
45 eth_frame.etherType_or_len = t;
46 } else {
47 eth_frame.kind = ether_kind::ETHER_TYPE;
48 eth_frame.etherType_or_len = t;
49 }
50
51 if(frame.size() < offset)
52 throw std::runtime_error("internal parse error (offset beyond frame)");
53
54 eth_frame.payload = frame.subspan(offset);
55 return eth_frame;
56}
57} // namespace eth
ETH TLM utilities.
Definition eth_tlm.cpp:2