blob: c9f6c90f3280663443ec42a563962a05cf7fc345 [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;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080022 int fd;
23 unsigned long bus_id;
24
25 /* receive buffer and state */
26 uint8_t rxbuf[1024];
27 struct mctp_pktbuf *rx_pkt;
28 uint8_t rx_exp_len;
29 uint16_t rx_fcs;
30 enum {
31 STATE_WAIT_SYNC_START,
32 STATE_WAIT_REVISION,
33 STATE_WAIT_LEN,
34 STATE_DATA,
35 STATE_DATA_ESCAPED,
36 STATE_WAIT_FCS1,
37 STATE_WAIT_FCS2,
38 STATE_WAIT_SYNC_END,
39 } rx_state;
Jeremy Kerrc67605b2019-02-07 21:52:00 +080040
41 /* temporary transmit buffer */
42 uint8_t txbuf[256];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080043};
44
45#ifndef container_of
46#define container_of(ptr, type, member) \
47 (type *)((char *)(ptr) - (char *)&((type *)0)->member)
48#endif
49
50#define binding_to_serial(b) \
51 container_of(b, struct mctp_binding_serial, binding)
52
53#define MCTP_SERIAL_REVISION 0x01
54#define MCTP_SERIAL_FRAMING_FLAG 0x7e
55#define MCTP_SERIAL_ESCAPE 0x7d
56
57struct mctp_serial_header {
58 uint8_t flag;
59 uint8_t revision;
60 uint8_t len;
61};
62
63struct mctp_serial_trailer {
64 uint8_t fcs_msb;
65 uint8_t fcs_lsb;
66 uint8_t flag;
67};
68
Jeremy Kerrc67605b2019-02-07 21:52:00 +080069static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080070{
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080071 uint8_t total_len;
Jeremy Kerrc67605b2019-02-07 21:52:00 +080072 uint8_t *p;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080073 int i, j;
74
75 total_len = pkt->end - pkt->mctp_hdr_off;
76
77 p = (void *)mctp_pktbuf_hdr(pkt);
78
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080079 for (i = 0, j = 0; i < total_len; i++, j++) {
Jeremy Kerrc67605b2019-02-07 21:52:00 +080080 uint8_t c = p[i];
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080081 if (c == 0x7e || c == 0x7d) {
Jeremy Kerrc67605b2019-02-07 21:52:00 +080082 if (buf)
83 buf[j] = 0x7d;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080084 j++;
85 c ^= 0x20;
86 }
Jeremy Kerrc67605b2019-02-07 21:52:00 +080087 if (buf)
88 buf[j] = c;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080089 }
Jeremy Kerrc67605b2019-02-07 21:52:00 +080090
91 return j;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +080092}
93
94static int mctp_binding_serial_tx(struct mctp_binding *b,
95 struct mctp_pktbuf *pkt)
96{
97 struct mctp_binding_serial *serial = binding_to_serial(b);
98 struct mctp_serial_header *hdr;
99 struct mctp_serial_trailer *tlr;
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800100 uint8_t *buf;
101 size_t len;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800102
103 /* the length field in the header excludes serial framing
104 * and escape sequences */
105 len = mctp_pktbuf_size(pkt);
106
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800107 hdr = (void *)serial->txbuf;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800108 hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
109 hdr->revision = MCTP_SERIAL_REVISION;
110 hdr->len = len;
111
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800112 buf = (void *)(hdr + 1);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800113
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800114 len = mctp_serial_pkt_escape(pkt, NULL);
115 if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
116 return -1;
117
118 mctp_serial_pkt_escape(pkt, buf);
119
120 buf += len;
121
122 tlr = (void *)buf;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800123 tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800124 /* todo: trailer FCS */
125 tlr->fcs_msb = 0;
126 tlr->fcs_lsb = 0;
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800127
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800128 write(serial->fd, serial->txbuf, sizeof(*hdr) + len + sizeof(*tlr));
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800129
130 return 0;
131}
132
133static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
134 bool valid)
135{
136 struct mctp_pktbuf *pkt = serial->rx_pkt;
137 assert(pkt);
138
139 if (valid)
Jeremy Kerr0a00dca2019-03-01 08:01:35 +0800140 mctp_bus_rx(&serial->binding, pkt);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800141
142 mctp_pktbuf_free(pkt);
143 serial->rx_pkt = NULL;
144}
145
146static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
147 uint8_t len)
148{
149 serial->rx_pkt = mctp_pktbuf_alloc(len);
150}
151
152static void mctp_rx_consume_one(struct mctp_binding_serial *serial,
153 uint8_t c)
154{
155 struct mctp_pktbuf *pkt = serial->rx_pkt;
156
157 mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
158
159 assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
160 serial->rx_state == STATE_WAIT_REVISION ||
161 serial->rx_state == STATE_WAIT_LEN));
162
163 switch (serial->rx_state) {
164 case STATE_WAIT_SYNC_START:
165 if (c != MCTP_SERIAL_FRAMING_FLAG) {
166 mctp_prdebug("lost sync, dropping packet");
167 if (pkt)
168 mctp_serial_finish_packet(serial, false);
169 } else {
170 serial->rx_state = STATE_WAIT_REVISION;
171 }
172 break;
173
174 case STATE_WAIT_REVISION:
175 if (c == MCTP_SERIAL_REVISION) {
176 serial->rx_state = STATE_WAIT_LEN;
177 } else {
178 mctp_prdebug("invalid revision 0x%02x", c);
179 serial->rx_state = STATE_WAIT_SYNC_START;
180 }
181 break;
182 case STATE_WAIT_LEN:
Jeremy Kerrc67605b2019-02-07 21:52:00 +0800183 if (c > (MCTP_MTU + sizeof(struct mctp_hdr))
184 || c < sizeof(struct mctp_hdr)) {
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800185 mctp_prdebug("invalid size %d", c);
186 serial->rx_state = STATE_WAIT_SYNC_START;
187 } else {
188 uint8_t *p;
189
190 mctp_serial_start_packet(serial, 0);
191 pkt = serial->rx_pkt;
192 p = mctp_pktbuf_alloc_start(pkt, 3);
193 p[0] = MCTP_SERIAL_FRAMING_FLAG;
194 p[1] = MCTP_SERIAL_REVISION;
195 p[2] = c;
196 serial->rx_exp_len = c;
197 serial->rx_state = STATE_DATA;
198 }
199 break;
200
201 case STATE_DATA:
202 if (c == MCTP_SERIAL_ESCAPE) {
203 serial->rx_state = STATE_DATA_ESCAPED;
204 } else {
205 mctp_pktbuf_push(pkt, &c, 1);
206 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
207 serial->rx_state = STATE_WAIT_FCS1;
208 }
209 break;
210
211 case STATE_DATA_ESCAPED:
212 c ^= 0x20;
213 mctp_pktbuf_push(pkt, &c, 1);
214 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
215 serial->rx_state = STATE_WAIT_FCS1;
216 else
217 serial->rx_state = STATE_DATA;
218 break;
219
220 case STATE_WAIT_FCS1:
221 serial->rx_fcs = c << 8;
222 serial->rx_state = STATE_WAIT_FCS2;
223 break;
224 case STATE_WAIT_FCS2:
225 serial->rx_fcs |= c;
226 /* todo: check fcs */
227 serial->rx_state = STATE_WAIT_SYNC_END;
228 break;
229
230 case STATE_WAIT_SYNC_END:
231 if (c == MCTP_SERIAL_FRAMING_FLAG) {
232 mctp_serial_finish_packet(serial, true);
233 } else {
234 mctp_prdebug("missing end frame marker");
235 mctp_serial_finish_packet(serial, false);
236 }
237 serial->rx_state = STATE_WAIT_SYNC_START;
238 break;
239 }
240
241 mctp_prdebug(" -> state: %d", serial->rx_state);
242}
243static void __attribute__((used)) mctp_rx_consume(struct mctp_binding_serial *serial,
244 void *buf, size_t len)
245{
246 size_t i;
247
248 for (i = 0; i < len; i++)
249 mctp_rx_consume_one(serial, *(uint8_t *)(buf + i));
250}
251
252#ifdef MCTP_FILEIO
253int mctp_serial_read(struct mctp_binding_serial *serial)
254{
255 ssize_t len;
256
257 len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
258 if (len == 0)
259 return -1;
260
261 if (len < 0) {
262 mctp_prerr("can't read from serial device: %m");
263 return -1;
264 }
265
266 mctp_rx_consume(serial, serial->rxbuf, len);
267
268 return 0;
269}
270
271int mctp_serial_get_fd(struct mctp_binding_serial *serial)
272{
273 return serial->fd;
274}
275
276int mctp_serial_open_path(struct mctp_binding_serial *serial,
277 const char *device)
278{
279 serial->fd = open(device, O_RDWR);
280 if (serial->fd < 0)
281 mctp_prerr("can't open device %s: %m", device);
282
283 return 0;
284}
285
286void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
287{
288 serial->fd = fd;
289}
290#endif
291
292void mctp_serial_register_bus(struct mctp_binding_serial *serial,
293 struct mctp *mctp, mctp_eid_t eid)
294{
295 assert(serial->fd >= 0);
Jeremy Kerr7520cec2019-03-01 07:13:18 +0800296 mctp_register_bus(mctp, &serial->binding, eid);
Jeremy Kerr4cdc2002019-02-07 16:49:12 +0800297}
298
299struct mctp_binding_serial *mctp_serial_init(void)
300{
301 struct mctp_binding_serial *serial;
302
303 serial = __mctp_alloc(sizeof(*serial));
304 serial->fd = -1;
305 serial->rx_state = STATE_WAIT_SYNC_START;
306 serial->rx_pkt = NULL;
307 serial->binding.name = "serial";
308 serial->binding.version = 1;
309
310 serial->binding.tx = mctp_binding_serial_tx;
311
312 return serial;
313}
314