blob: 482cedbb8876c03331679568c5fddda11f9445f4 [file] [log] [blame]
Jeremy Kerr4cdc2002019-02-07 16:49:12 +08001/* SPDX-License-Identifier: Apache-2.0 */
2
3#include <assert.h>
4#include <stdbool.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8
9#ifdef MCTP_FILEIO
10#include <fcntl.h>
11#endif
12
13#define pr_fmt(x) "serial: " x
14
15#include "libmctp.h"
16#include "libmctp-alloc.h"
17#include "libmctp-log.h"
18#include "libmctp-serial.h"
19
20struct mctp_binding_serial {
21 struct mctp_binding binding;
22 struct mctp *mctp;
23 int fd;
24 unsigned long bus_id;
25
26 /* receive buffer and state */
27 uint8_t rxbuf[1024];
28 struct mctp_pktbuf *rx_pkt;
29 uint8_t rx_exp_len;
30 uint16_t rx_fcs;
31 enum {
32 STATE_WAIT_SYNC_START,
33 STATE_WAIT_REVISION,
34 STATE_WAIT_LEN,
35 STATE_DATA,
36 STATE_DATA_ESCAPED,
37 STATE_WAIT_FCS1,
38 STATE_WAIT_FCS2,
39 STATE_WAIT_SYNC_END,
40 } rx_state;
Jeremy Kerrc67605b2019-02-07 21:52:00 +080041
42 /* temporary transmit buffer */
43 uint8_t txbuf[256];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080044};
45
46#ifndef container_of
47#define container_of(ptr, type, member) \
48 (type *)((char *)(ptr) - (char *)&((type *)0)->member)
49#endif
50
51#define binding_to_serial(b) \
52 container_of(b, struct mctp_binding_serial, binding)
53
54#define MCTP_SERIAL_REVISION 0x01
55#define MCTP_SERIAL_FRAMING_FLAG 0x7e
56#define MCTP_SERIAL_ESCAPE 0x7d
57
58struct mctp_serial_header {
59 uint8_t flag;
60 uint8_t revision;
61 uint8_t len;
62};
63
64struct mctp_serial_trailer {
65 uint8_t fcs_msb;
66 uint8_t fcs_lsb;
67 uint8_t flag;
68};
69
Jeremy Kerrc67605b2019-02-07 21:52:00 +080070static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080071{
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080072 uint8_t total_len;
Jeremy Kerrc67605b2019-02-07 21:52:00 +080073 uint8_t *p;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080074 int i, j;
75
76 total_len = pkt->end - pkt->mctp_hdr_off;
77
78 p = (void *)mctp_pktbuf_hdr(pkt);
79
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080080 for (i = 0, j = 0; i < total_len; i++, j++) {
Jeremy Kerrc67605b2019-02-07 21:52:00 +080081 uint8_t c = p[i];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080082 if (c == 0x7e || c == 0x7d) {
Jeremy Kerrc67605b2019-02-07 21:52:00 +080083 if (buf)
84 buf[j] = 0x7d;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080085 j++;
86 c ^= 0x20;
87 }
Jeremy Kerrc67605b2019-02-07 21:52:00 +080088 if (buf)
89 buf[j] = c;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080090 }
Jeremy Kerrc67605b2019-02-07 21:52:00 +080091
92 return j;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080093}
94
95static int mctp_binding_serial_tx(struct mctp_binding *b,
96 struct mctp_pktbuf *pkt)
97{
98 struct mctp_binding_serial *serial = binding_to_serial(b);
99 struct mctp_serial_header *hdr;
100 struct mctp_serial_trailer *tlr;
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800101 uint8_t *buf;
102 size_t len;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800103
104 /* the length field in the header excludes serial framing
105 * and escape sequences */
106 len = mctp_pktbuf_size(pkt);
107
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800108 hdr = (void *)serial->txbuf;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800109 hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
110 hdr->revision = MCTP_SERIAL_REVISION;
111 hdr->len = len;
112
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800113 buf = (void *)(hdr + 1);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800114
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800115 len = mctp_serial_pkt_escape(pkt, NULL);
116 if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
117 return -1;
118
119 mctp_serial_pkt_escape(pkt, buf);
120
121 buf += len;
122
123 tlr = (void *)buf;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800124 tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800125 /* todo: trailer FCS */
126 tlr->fcs_msb = 0;
127 tlr->fcs_lsb = 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800128
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800129 write(serial->fd, serial->txbuf, sizeof(*hdr) + len + sizeof(*tlr));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800130
131 return 0;
132}
133
134static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
135 bool valid)
136{
137 struct mctp_pktbuf *pkt = serial->rx_pkt;
138 assert(pkt);
139
140 if (valid)
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800141 mctp_bus_rx(serial->mctp, &serial->binding, pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800142
143 mctp_pktbuf_free(pkt);
144 serial->rx_pkt = NULL;
145}
146
147static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
148 uint8_t len)
149{
150 serial->rx_pkt = mctp_pktbuf_alloc(len);
151}
152
153static void mctp_rx_consume_one(struct mctp_binding_serial *serial,
154 uint8_t c)
155{
156 struct mctp_pktbuf *pkt = serial->rx_pkt;
157
158 mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
159
160 assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
161 serial->rx_state == STATE_WAIT_REVISION ||
162 serial->rx_state == STATE_WAIT_LEN));
163
164 switch (serial->rx_state) {
165 case STATE_WAIT_SYNC_START:
166 if (c != MCTP_SERIAL_FRAMING_FLAG) {
167 mctp_prdebug("lost sync, dropping packet");
168 if (pkt)
169 mctp_serial_finish_packet(serial, false);
170 } else {
171 serial->rx_state = STATE_WAIT_REVISION;
172 }
173 break;
174
175 case STATE_WAIT_REVISION:
176 if (c == MCTP_SERIAL_REVISION) {
177 serial->rx_state = STATE_WAIT_LEN;
178 } else {
179 mctp_prdebug("invalid revision 0x%02x", c);
180 serial->rx_state = STATE_WAIT_SYNC_START;
181 }
182 break;
183 case STATE_WAIT_LEN:
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800184 if (c > (MCTP_MTU + sizeof(struct mctp_hdr))
185 || c < sizeof(struct mctp_hdr)) {
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800186 mctp_prdebug("invalid size %d", c);
187 serial->rx_state = STATE_WAIT_SYNC_START;
188 } else {
189 uint8_t *p;
190
191 mctp_serial_start_packet(serial, 0);
192 pkt = serial->rx_pkt;
193 p = mctp_pktbuf_alloc_start(pkt, 3);
194 p[0] = MCTP_SERIAL_FRAMING_FLAG;
195 p[1] = MCTP_SERIAL_REVISION;
196 p[2] = c;
197 serial->rx_exp_len = c;
198 serial->rx_state = STATE_DATA;
199 }
200 break;
201
202 case STATE_DATA:
203 if (c == MCTP_SERIAL_ESCAPE) {
204 serial->rx_state = STATE_DATA_ESCAPED;
205 } else {
206 mctp_pktbuf_push(pkt, &c, 1);
207 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
208 serial->rx_state = STATE_WAIT_FCS1;
209 }
210 break;
211
212 case STATE_DATA_ESCAPED:
213 c ^= 0x20;
214 mctp_pktbuf_push(pkt, &c, 1);
215 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
216 serial->rx_state = STATE_WAIT_FCS1;
217 else
218 serial->rx_state = STATE_DATA;
219 break;
220
221 case STATE_WAIT_FCS1:
222 serial->rx_fcs = c << 8;
223 serial->rx_state = STATE_WAIT_FCS2;
224 break;
225 case STATE_WAIT_FCS2:
226 serial->rx_fcs |= c;
227 /* todo: check fcs */
228 serial->rx_state = STATE_WAIT_SYNC_END;
229 break;
230
231 case STATE_WAIT_SYNC_END:
232 if (c == MCTP_SERIAL_FRAMING_FLAG) {
233 mctp_serial_finish_packet(serial, true);
234 } else {
235 mctp_prdebug("missing end frame marker");
236 mctp_serial_finish_packet(serial, false);
237 }
238 serial->rx_state = STATE_WAIT_SYNC_START;
239 break;
240 }
241
242 mctp_prdebug(" -> state: %d", serial->rx_state);
243}
244static void __attribute__((used)) mctp_rx_consume(struct mctp_binding_serial *serial,
245 void *buf, size_t len)
246{
247 size_t i;
248
249 for (i = 0; i < len; i++)
250 mctp_rx_consume_one(serial, *(uint8_t *)(buf + i));
251}
252
253#ifdef MCTP_FILEIO
254int mctp_serial_read(struct mctp_binding_serial *serial)
255{
256 ssize_t len;
257
258 len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
259 if (len == 0)
260 return -1;
261
262 if (len < 0) {
263 mctp_prerr("can't read from serial device: %m");
264 return -1;
265 }
266
267 mctp_rx_consume(serial, serial->rxbuf, len);
268
269 return 0;
270}
271
272int mctp_serial_get_fd(struct mctp_binding_serial *serial)
273{
274 return serial->fd;
275}
276
277int mctp_serial_open_path(struct mctp_binding_serial *serial,
278 const char *device)
279{
280 serial->fd = open(device, O_RDWR);
281 if (serial->fd < 0)
282 mctp_prerr("can't open device %s: %m", device);
283
284 return 0;
285}
286
287void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
288{
289 serial->fd = fd;
290}
291#endif
292
293void mctp_serial_register_bus(struct mctp_binding_serial *serial,
294 struct mctp *mctp, mctp_eid_t eid)
295{
296 assert(serial->fd >= 0);
297 serial->mctp = mctp;
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800298 mctp_register_bus(mctp, &serial->binding, eid);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800299}
300
301struct mctp_binding_serial *mctp_serial_init(void)
302{
303 struct mctp_binding_serial *serial;
304
305 serial = __mctp_alloc(sizeof(*serial));
306 serial->fd = -1;
307 serial->rx_state = STATE_WAIT_SYNC_START;
308 serial->rx_pkt = NULL;
309 serial->binding.name = "serial";
310 serial->binding.version = 1;
311
312 serial->binding.tx = mctp_binding_serial_tx;
313
314 return serial;
315}
316