DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
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
11#if DETWS_ENABLE_RAWL2
12
13#include <string.h>
14
15size_t detws_eth_build(const uint8_t *dst, const uint8_t *src, uint16_t ethertype, const uint8_t *payload,
16 size_t payload_len, uint8_t *out, size_t cap)
17{
18 if (!dst || !src || !out || (payload_len && !payload))
19 return 0;
20 size_t n = RawL2::ETH_HDR_LEN + payload_len;
21 if (n > cap)
22 return 0;
23 memcpy(out, dst, RawL2::ETH_ALEN);
24 memcpy(out + RawL2::ETH_ALEN, src, RawL2::ETH_ALEN);
25 out[12] = (uint8_t)(ethertype >> 8);
26 out[13] = (uint8_t)ethertype;
27 if (payload_len)
28 memcpy(out + RawL2::ETH_HDR_LEN, payload, payload_len);
29 return n;
30}
31
32size_t detws_eth_build_vlan(const uint8_t *dst, const uint8_t *src, uint8_t pcp, bool dei, uint16_t vid,
33 uint16_t ethertype, const uint8_t *payload, size_t payload_len, uint8_t *out, size_t cap)
34{
35 if (!dst || !src || !out || (payload_len && !payload))
36 return 0;
37 size_t n = RawL2::ETH_VLAN_HDR_LEN + payload_len;
38 if (n > cap)
39 return 0;
40 memcpy(out, dst, RawL2::ETH_ALEN);
41 memcpy(out + RawL2::ETH_ALEN, src, RawL2::ETH_ALEN);
42 out[12] = (uint8_t)(RawL2::ETH_TPID_8021Q >> 8);
43 out[13] = (uint8_t)RawL2::ETH_TPID_8021Q;
44 uint16_t tci = (uint16_t)(((pcp & 0x7) << 13) | ((dei ? 1 : 0) << 12) | (vid & 0x0FFF));
45 out[14] = (uint8_t)(tci >> 8);
46 out[15] = (uint8_t)tci;
47 out[16] = (uint8_t)(ethertype >> 8);
48 out[17] = (uint8_t)ethertype;
49 if (payload_len)
50 memcpy(out + RawL2::ETH_VLAN_HDR_LEN, payload, payload_len);
51 return n;
52}
53
54bool detws_eth_parse(const uint8_t *frame, size_t len, EthFrame *out)
55{
56 if (!frame || !out || len < RawL2::ETH_HDR_LEN)
57 return false;
58 out->dst = frame;
59 out->src = frame + RawL2::ETH_ALEN;
60 uint16_t et = (uint16_t)((frame[12] << 8) | frame[13]);
61 if (et == RawL2::ETH_TPID_8021Q)
62 {
63 if (len < RawL2::ETH_VLAN_HDR_LEN)
64 return false;
65 uint16_t tci = (uint16_t)((frame[14] << 8) | frame[15]);
66 out->vlan = true;
67 out->pcp = (uint8_t)((tci >> 13) & 0x7);
68 out->vid = (uint16_t)(tci & 0x0FFF);
69 out->ethertype = (uint16_t)((frame[16] << 8) | frame[17]);
70 out->payload = frame + RawL2::ETH_VLAN_HDR_LEN;
71 out->payload_len = len - RawL2::ETH_VLAN_HDR_LEN;
72 }
73 else
74 {
75 out->vlan = false;
76 out->pcp = 0;
77 out->vid = 0;
78 out->ethertype = et;
79 out->payload = frame + RawL2::ETH_HDR_LEN;
80 out->payload_len = len - RawL2::ETH_HDR_LEN;
81 }
82 return true;
83}
84
85uint32_t detws_eth_fcs(const uint8_t *bytes, size_t len)
86{
87 // CRC-32/ISO-HDLC (the Ethernet FCS): reflected poly 0xEDB88320, init/xorout 0xFFFFFFFF.
88 uint32_t crc = 0xFFFFFFFFu;
89 for (size_t i = 0; i < len; i++)
90 {
91 crc ^= bytes[i];
92 for (int b = 0; b < 8; b++)
93 crc = (crc >> 1) ^ (0xEDB88320u & (uint32_t)(-(int32_t)(crc & 1)));
94 }
95 return ~crc;
96}
97
98#endif // DETWS_ENABLE_RAWL2
Raw Layer-2 Ethernet frame codec (DETWS_ENABLE_RAWL2).