DeterministicESPAsyncWebServer v6.27.1
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
cotp.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 cotp.cpp
6 * @brief TPKT + COTP (X.224 class 0) frame builder + parser (pure, host-tested).
7 */
8
10
11#if DETWS_ENABLE_COTP
12
13#include <string.h>
14
15size_t tpkt_build(uint8_t *buf, size_t cap, const uint8_t *payload, size_t payload_len)
16{
17 if (!buf || (payload_len && !payload))
18 return 0;
19 size_t total = TPKT_HEADER_SIZE + payload_len;
20 if (total > 0xFFFF || total > cap)
21 return 0;
22 buf[0] = TPKT_VERSION;
23 buf[1] = 0x00; // reserved
24 buf[2] = (uint8_t)(total >> 8); // length, big-endian, whole packet
25 buf[3] = (uint8_t)(total & 0xFF);
26 if (payload_len)
27 memcpy(buf + TPKT_HEADER_SIZE, payload, payload_len);
28 return total;
29}
30
31bool tpkt_parse(const uint8_t *buf, size_t len, const uint8_t **payload, size_t *payload_len, size_t *consumed)
32{
33 if (!buf || len < TPKT_HEADER_SIZE)
34 return false;
35 if (buf[0] != TPKT_VERSION)
36 return false;
37 size_t total = ((size_t)buf[2] << 8) | buf[3];
38 if (total < TPKT_HEADER_SIZE || total > len)
39 return false; // invalid / not fully buffered
40 if (payload)
41 *payload = buf + TPKT_HEADER_SIZE;
42 if (payload_len)
43 *payload_len = total - TPKT_HEADER_SIZE;
44 if (consumed)
45 *consumed = total;
46 return true;
47}
48
49size_t cotp_build_dt(uint8_t *buf, size_t cap, const uint8_t *data, size_t data_len, bool eot)
50{
51 if (!buf || (data_len && !data))
52 return 0;
53 size_t total = COTP_DT_HEADER_LEN + data_len;
54 if (total > cap)
55 return 0;
56 buf[0] = COTP_DT_HEADER_LEN - 1; // LI = octets after LI (code + nr/eot)
57 buf[1] = COTP_DT; // Data TPDU
58 buf[2] = (uint8_t)(eot ? COTP_EOT : 0); // EOT flag | TPDU-NR (0 for class 0)
59 if (data_len)
60 memcpy(buf + COTP_DT_HEADER_LEN, data, data_len);
61 return total;
62}
63
64size_t cotp_build_cr(uint8_t *buf, size_t cap, uint16_t src_ref, uint8_t tpdu_size_code, const uint8_t *extra_params,
65 size_t extra_len)
66{
67 if (!buf || (extra_len && !extra_params))
68 return 0;
69 // header after LI: code(1) dst-ref(2) src-ref(2) class(1) + tpdu-size param(3) + extras
70 size_t after_li = 1 + 2 + 2 + 1 + 3 + extra_len;
71 size_t total = 1 + after_li; // + the LI octet itself
72 if (after_li > 0xFF || total > cap)
73 return 0;
74 size_t p = 0;
75 buf[p++] = (uint8_t)after_li; // LI
76 buf[p++] = COTP_CR;
77 buf[p++] = 0x00; // dst-ref = 0 (unknown on a request)
78 buf[p++] = 0x00;
79 buf[p++] = (uint8_t)(src_ref >> 8);
80 buf[p++] = (uint8_t)(src_ref & 0xFF);
81 buf[p++] = 0x00; // class 0, no options
82 buf[p++] = COTP_PARAM_TPDU_SIZE;
83 buf[p++] = 0x01; // parameter length
84 buf[p++] = tpdu_size_code;
85 if (extra_len)
86 {
87 memcpy(buf + p, extra_params, extra_len);
88 p += extra_len;
89 }
90 return p;
91}
92
93bool cotp_parse(const uint8_t *buf, size_t len, CotpHeader *out)
94{
95 if (!buf || !out || len < 2)
96 return false;
97 uint8_t li = buf[0];
98 size_t header = (size_t)li + 1; // LI counts the octets after itself
99 if (header > len || li < 1)
100 return false;
101
102 out->code = (uint8_t)(buf[1] & 0xF0); // type is the high nibble
103 out->dst_ref = 0;
104 out->src_ref = 0;
105 out->eot = false;
106 out->data = nullptr;
107 out->data_len = 0;
108
109 if (out->code == COTP_DT)
110 {
111 if (li < 2) // need the TPDU-NR/EOT octet
112 return false;
113 out->eot = (buf[2] & COTP_EOT) != 0;
114 out->data = buf + header;
115 out->data_len = len - header;
116 return true;
117 }
118 if (out->code == COTP_CR || out->code == COTP_CC)
119 {
120 if (li < 6) // code + dst-ref(2) + src-ref(2) + class(1)
121 return false;
122 out->dst_ref = (uint16_t)((buf[2] << 8) | buf[3]);
123 out->src_ref = (uint16_t)((buf[4] << 8) | buf[5]);
124 return true;
125 }
126 // Other TPDU types (DR/DC/ER/...): the type code is reported; no body extracted.
127 return true;
128}
129
130#endif // DETWS_ENABLE_COTP
TPKT (RFC 1006) + COTP / ISO 8073 X.224 class-0 frame codec (DETWS_ENABLE_COTP) - zero-heap "ISO tran...