ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
rawl2.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file rawl2.cpp
6 * @brief Raw Layer-2 Ethernet frame codec (see rawl2.h).
7 */
8
10#include "shared_primitives/crc.h" // PC_CRC32_ISO_HDLC
11
12#if PC_ENABLE_RAWL2
13
14#include <string.h>
15
16size_t pc_eth_build(const uint8_t *dst, const uint8_t *src, uint16_t ethertype, const uint8_t *payload,
17 size_t payload_len, uint8_t *out, size_t cap)
18{
19 if (!dst || !src || !out || (payload_len && !payload))
20 {
21 return 0;
22 }
23 size_t n = RawL2::ETH_HDR_LEN + payload_len;
24 if (n > cap)
25 {
26 return 0;
27 }
28 memcpy(out, dst, RawL2::ETH_ALEN);
29 memcpy(out + RawL2::ETH_ALEN, src, RawL2::ETH_ALEN);
30 out[12] = (uint8_t)(ethertype >> 8);
31 out[13] = (uint8_t)ethertype;
32 if (payload_len)
33 {
34 memcpy(out + RawL2::ETH_HDR_LEN, payload, payload_len);
35 }
36 return n;
37}
38
39size_t pc_eth_build_vlan(const uint8_t *dst, const uint8_t *src, uint8_t pcp, bool dei, uint16_t vid,
40 uint16_t ethertype, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t cap)
41{
42 if (!dst || !src || !out || (payload_len && !payload))
43 {
44 return 0;
45 }
46 size_t n = RawL2::ETH_VLAN_HDR_LEN + payload_len;
47 if (n > cap)
48 {
49 return 0;
50 }
51 memcpy(out, dst, RawL2::ETH_ALEN);
52 memcpy(out + RawL2::ETH_ALEN, src, RawL2::ETH_ALEN);
53 out[12] = (uint8_t)(RawL2::ETH_TPID_8021Q >> 8);
54 out[13] = (uint8_t)RawL2::ETH_TPID_8021Q;
55 uint16_t tci = (uint16_t)(((pcp & 0x7) << 13) | ((dei ? 1 : 0) << 12) | (vid & 0x0FFF));
56 out[14] = (uint8_t)(tci >> 8);
57 out[15] = (uint8_t)tci;
58 out[16] = (uint8_t)(ethertype >> 8);
59 out[17] = (uint8_t)ethertype;
60 if (payload_len)
61 {
62 memcpy(out + RawL2::ETH_VLAN_HDR_LEN, payload, payload_len);
63 }
64 return n;
65}
66
67bool pc_eth_parse(const uint8_t *frame, size_t len, EthFrame *out)
68{
69 if (!frame || !out || len < RawL2::ETH_HDR_LEN)
70 {
71 return false;
72 }
73 out->dst = frame;
74 out->src = frame + RawL2::ETH_ALEN;
75 uint16_t et = (uint16_t)((frame[12] << 8) | frame[13]);
76 if (et == RawL2::ETH_TPID_8021Q)
77 {
78 if (len < RawL2::ETH_VLAN_HDR_LEN)
79 {
80 return false;
81 }
82 uint16_t tci = (uint16_t)((frame[14] << 8) | frame[15]);
83 out->vlan = true;
84 out->pcp = (uint8_t)((tci >> 13) & 0x7);
85 out->vid = (uint16_t)(tci & 0x0FFF);
86 out->ethertype = (uint16_t)((frame[16] << 8) | frame[17]);
87 out->payload = frame + RawL2::ETH_VLAN_HDR_LEN;
88 out->payload_len = len - RawL2::ETH_VLAN_HDR_LEN;
89 }
90 else
91 {
92 out->vlan = false;
93 out->pcp = 0;
94 out->vid = 0;
95 out->ethertype = et;
96 out->payload = frame + RawL2::ETH_HDR_LEN;
97 out->payload_len = len - RawL2::ETH_HDR_LEN;
98 }
99 return true;
100}
101
102uint32_t pc_eth_fcs(const uint8_t *bytes, size_t len)
103{
104 // CRC-32/ISO-HDLC (the Ethernet FCS): reflected poly 0xEDB88320, init/xorout 0xFFFFFFFF.
105 // test_crc diffs the shared engine against the loop that used to live here over every length
106 // 0..64, so this is byte-identical to it.
107 return pc_crc(&PC_CRC32_ISO_HDLC, bytes, len);
108}
109
110#endif // PC_ENABLE_RAWL2
Parameterized CRC engine - one source of truth for every cyclic redundancy check.
constexpr pc_crc_params PC_CRC32_ISO_HDLC
CRC-32/ISO-HDLC (zlib / PKZIP / Ethernet). check = 0xCBF43926.
Definition crc.h:198
uint32_t pc_crc(const pc_crc_params *p, const uint8_t *data, size_t len)
One-shot CRC of len octets at data.
Definition crc.h:158
Raw Layer-2 Ethernet frame codec (PC_ENABLE_RAWL2).