1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "crc-16-ccitt.h"
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14
15 #ifdef MCTP_HAVE_FILEIO
16 #include <fcntl.h>
17 #include <poll.h>
18 #include <unistd.h>
19 #else
write(int fd,void * buf,size_t len)20 static const size_t write(int fd, void *buf, size_t len)
21 {
22 return -1;
23 }
24 #endif
25
26 #define pr_fmt(x) "serial: " x
27
28 /*
29 * @fn: A function that will copy data from the buffer at src into the dst object
30 * @dst: An opaque object to pass as state to fn
31 * @src: A pointer to the buffer of data to copy to dst
32 * @len: The length of the data pointed to by src
33 * @return: 0 on succes, negative error code on failure
34 *
35 * Pre-condition: fn returns a write count or a negative error code
36 * Post-condition: All bytes written or an error has occurred
37 */
38 #define mctp_write_all(fn, dst, src, len) \
39 ({ \
40 typeof(src) __src = src; \
41 ssize_t wrote; \
42 while (len) { \
43 wrote = fn(dst, __src, len); \
44 if (wrote < 0) \
45 break; \
46 __src += wrote; \
47 len -= wrote; \
48 } \
49 len ? wrote : 0; \
50 })
51
mctp_serial_write(int fildes,const void * buf,size_t nbyte)52 static ssize_t mctp_serial_write(int fildes, const void *buf, size_t nbyte)
53 {
54 ssize_t wrote;
55
56 return ((wrote = write(fildes, buf, nbyte)) < 0) ? -errno : wrote;
57 }
58
59 #include "libmctp.h"
60 #include "libmctp-alloc.h"
61 #include "libmctp-log.h"
62 #include "libmctp-serial.h"
63 #include "container_of.h"
64
65 struct mctp_binding_serial {
66 struct mctp_binding binding;
67 int fd;
68 unsigned long bus_id;
69
70 mctp_serial_tx_fn tx_fn;
71 void *tx_fn_data;
72
73 /* receive buffer and state */
74 uint8_t rxbuf[1024];
75 struct mctp_pktbuf *rx_pkt;
76 uint8_t rx_exp_len;
77 uint16_t rx_fcs;
78 uint16_t rx_fcs_calc;
79 enum {
80 STATE_WAIT_SYNC_START,
81 STATE_WAIT_REVISION,
82 STATE_WAIT_LEN,
83 STATE_DATA,
84 STATE_DATA_ESCAPED,
85 STATE_WAIT_FCS1,
86 STATE_WAIT_FCS2,
87 STATE_WAIT_SYNC_END,
88 } rx_state;
89
90 /* temporary transmit buffer */
91 uint8_t txbuf[256];
92 };
93
94 #define binding_to_serial(b) \
95 container_of(b, struct mctp_binding_serial, binding)
96
97 #define MCTP_SERIAL_REVISION 0x01
98 #define MCTP_SERIAL_FRAMING_FLAG 0x7e
99 #define MCTP_SERIAL_ESCAPE 0x7d
100
101 struct mctp_serial_header {
102 uint8_t flag;
103 uint8_t revision;
104 uint8_t len;
105 };
106
107 struct mctp_serial_trailer {
108 uint8_t fcs_msb;
109 uint8_t fcs_lsb;
110 uint8_t flag;
111 };
112
mctp_serial_pkt_escape(struct mctp_pktbuf * pkt,uint8_t * buf)113 static size_t mctp_serial_pkt_escape(struct mctp_pktbuf *pkt, uint8_t *buf)
114 {
115 uint8_t total_len;
116 uint8_t *p;
117 int i, j;
118
119 total_len = pkt->end - pkt->mctp_hdr_off;
120
121 p = (void *)mctp_pktbuf_hdr(pkt);
122
123 for (i = 0, j = 0; i < total_len; i++, j++) {
124 uint8_t c = p[i];
125 if (c == 0x7e || c == 0x7d) {
126 if (buf)
127 buf[j] = 0x7d;
128 j++;
129 c ^= 0x20;
130 }
131 if (buf)
132 buf[j] = c;
133 }
134
135 return j;
136 }
137
mctp_binding_serial_tx(struct mctp_binding * b,struct mctp_pktbuf * pkt)138 static int mctp_binding_serial_tx(struct mctp_binding *b,
139 struct mctp_pktbuf *pkt)
140 {
141 struct mctp_binding_serial *serial = binding_to_serial(b);
142 struct mctp_serial_header *hdr;
143 struct mctp_serial_trailer *tlr;
144 uint8_t *buf;
145 size_t len;
146 uint16_t fcs;
147
148 /* the length field in the header excludes serial framing
149 * and escape sequences */
150 len = mctp_pktbuf_size(pkt);
151
152 hdr = (void *)serial->txbuf;
153 hdr->flag = MCTP_SERIAL_FRAMING_FLAG;
154 hdr->revision = MCTP_SERIAL_REVISION;
155 hdr->len = len;
156
157 // Calculate fcs
158 fcs = crc_16_ccitt(FCS_INIT_16, (const uint8_t *)hdr + 1, 2);
159 fcs = crc_16_ccitt(fcs, (const uint8_t *)mctp_pktbuf_hdr(pkt), len);
160
161 buf = (void *)(hdr + 1);
162
163 len = mctp_serial_pkt_escape(pkt, NULL);
164 if (len + sizeof(*hdr) + sizeof(*tlr) > sizeof(serial->txbuf))
165 return -EMSGSIZE;
166
167 mctp_serial_pkt_escape(pkt, buf);
168
169 buf += len;
170
171 tlr = (void *)buf;
172 tlr->flag = MCTP_SERIAL_FRAMING_FLAG;
173 tlr->fcs_msb = fcs >> 8;
174 tlr->fcs_lsb = fcs & 0xff;
175
176 len += sizeof(*hdr) + sizeof(*tlr);
177
178 if (!serial->tx_fn)
179 return mctp_write_all(mctp_serial_write, serial->fd,
180 &serial->txbuf[0], len);
181
182 return mctp_write_all(serial->tx_fn, serial->tx_fn_data,
183 &serial->txbuf[0], len);
184 }
185
mctp_serial_finish_packet(struct mctp_binding_serial * serial,bool valid)186 static void mctp_serial_finish_packet(struct mctp_binding_serial *serial,
187 bool valid)
188 {
189 struct mctp_pktbuf *pkt = serial->rx_pkt;
190 assert(pkt);
191
192 if (valid)
193 mctp_bus_rx(&serial->binding, pkt);
194
195 serial->rx_pkt = NULL;
196 }
197
mctp_serial_start_packet(struct mctp_binding_serial * serial,uint8_t len)198 static void mctp_serial_start_packet(struct mctp_binding_serial *serial,
199 uint8_t len)
200 {
201 serial->rx_pkt = mctp_pktbuf_alloc(&serial->binding, len);
202 }
203
mctp_rx_consume_one(struct mctp_binding_serial * serial,uint8_t c)204 static void mctp_rx_consume_one(struct mctp_binding_serial *serial, uint8_t c)
205 {
206 struct mctp_pktbuf *pkt = serial->rx_pkt;
207 bool valid = false;
208
209 mctp_prdebug("state: %d, char 0x%02x", serial->rx_state, c);
210
211 assert(!pkt == (serial->rx_state == STATE_WAIT_SYNC_START ||
212 serial->rx_state == STATE_WAIT_REVISION ||
213 serial->rx_state == STATE_WAIT_LEN));
214
215 switch (serial->rx_state) {
216 case STATE_WAIT_SYNC_START:
217 if (c != MCTP_SERIAL_FRAMING_FLAG) {
218 mctp_prdebug("lost sync, dropping packet");
219 if (pkt)
220 mctp_serial_finish_packet(serial, false);
221 } else {
222 serial->rx_state = STATE_WAIT_REVISION;
223 }
224 break;
225
226 case STATE_WAIT_REVISION:
227 if (c == MCTP_SERIAL_REVISION) {
228 serial->rx_state = STATE_WAIT_LEN;
229 serial->rx_fcs_calc = crc_16_ccitt_byte(FCS_INIT_16, c);
230 } else if (c == MCTP_SERIAL_FRAMING_FLAG) {
231 /* Handle the case where there are bytes dropped in request,
232 * and the state machine is out of sync. The failed request's
233 * trailing footer i.e. 0x7e would be interpreted as next
234 * request's framing footer. So if we are in STATE_WAIT_REVISION
235 * and receive 0x7e byte, then contine to stay in
236 * STATE_WAIT_REVISION
237 */
238 mctp_prdebug(
239 "Received serial framing flag 0x%02x while waiting"
240 " for serial revision 0x%02x.",
241 c, MCTP_SERIAL_REVISION);
242 } else {
243 mctp_prdebug("invalid revision 0x%02x", c);
244 serial->rx_state = STATE_WAIT_SYNC_START;
245 }
246 break;
247 case STATE_WAIT_LEN:
248 if (c > serial->binding.pkt_size ||
249 c < sizeof(struct mctp_hdr)) {
250 mctp_prdebug("invalid size %d", c);
251 serial->rx_state = STATE_WAIT_SYNC_START;
252 } else {
253 mctp_serial_start_packet(serial, 0);
254 pkt = serial->rx_pkt;
255 serial->rx_exp_len = c;
256 serial->rx_state = STATE_DATA;
257 serial->rx_fcs_calc =
258 crc_16_ccitt_byte(serial->rx_fcs_calc, c);
259 }
260 break;
261
262 case STATE_DATA:
263 if (c == MCTP_SERIAL_ESCAPE) {
264 serial->rx_state = STATE_DATA_ESCAPED;
265 } else {
266 mctp_pktbuf_push(pkt, &c, 1);
267 serial->rx_fcs_calc =
268 crc_16_ccitt_byte(serial->rx_fcs_calc, c);
269 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
270 serial->rx_state = STATE_WAIT_FCS1;
271 }
272 break;
273
274 case STATE_DATA_ESCAPED:
275 c ^= 0x20;
276 mctp_pktbuf_push(pkt, &c, 1);
277 serial->rx_fcs_calc = crc_16_ccitt_byte(serial->rx_fcs_calc, c);
278 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len)
279 serial->rx_state = STATE_WAIT_FCS1;
280 else
281 serial->rx_state = STATE_DATA;
282 break;
283
284 case STATE_WAIT_FCS1:
285 serial->rx_fcs = c << 8;
286 serial->rx_state = STATE_WAIT_FCS2;
287 break;
288 case STATE_WAIT_FCS2:
289 serial->rx_fcs |= c;
290 serial->rx_state = STATE_WAIT_SYNC_END;
291 break;
292
293 case STATE_WAIT_SYNC_END:
294 if (serial->rx_fcs == serial->rx_fcs_calc) {
295 if (c == MCTP_SERIAL_FRAMING_FLAG) {
296 valid = true;
297 } else {
298 valid = false;
299 mctp_prdebug("missing end frame marker");
300 }
301 } else {
302 valid = false;
303 mctp_prdebug("invalid fcs : 0x%04x, expect 0x%04x",
304 serial->rx_fcs, serial->rx_fcs_calc);
305 }
306
307 mctp_serial_finish_packet(serial, valid);
308 serial->rx_state = STATE_WAIT_SYNC_START;
309 break;
310 }
311
312 mctp_prdebug(" -> state: %d", serial->rx_state);
313 }
mctp_rx_consume(struct mctp_binding_serial * serial,const void * buf,size_t len)314 static void mctp_rx_consume(struct mctp_binding_serial *serial, const void *buf,
315 size_t len)
316 {
317 size_t i;
318
319 for (i = 0; i < len; i++)
320 mctp_rx_consume_one(serial, *(uint8_t *)(buf + i));
321 }
322
323 #ifdef MCTP_HAVE_FILEIO
mctp_serial_read(struct mctp_binding_serial * serial)324 int mctp_serial_read(struct mctp_binding_serial *serial)
325 {
326 ssize_t len;
327
328 len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf));
329 if (len == 0)
330 return -1;
331
332 if (len < 0) {
333 mctp_prerr("can't read from serial device: %m");
334 return -1;
335 }
336
337 mctp_rx_consume(serial, serial->rxbuf, len);
338
339 return 0;
340 }
341
mctp_serial_init_pollfd(struct mctp_binding_serial * serial,struct pollfd * pollfd)342 int mctp_serial_init_pollfd(struct mctp_binding_serial *serial,
343 struct pollfd *pollfd)
344 {
345 pollfd->fd = serial->fd;
346 pollfd->events = POLLIN;
347
348 return 0;
349 }
350
mctp_serial_open_path(struct mctp_binding_serial * serial,const char * device)351 int mctp_serial_open_path(struct mctp_binding_serial *serial,
352 const char *device)
353 {
354 serial->fd = open(device, O_RDWR);
355 if (serial->fd < 0)
356 mctp_prerr("can't open device %s: %m", device);
357
358 return 0;
359 }
360
mctp_serial_open_fd(struct mctp_binding_serial * serial,int fd)361 void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd)
362 {
363 serial->fd = fd;
364 }
365 #endif
366
mctp_serial_set_tx_fn(struct mctp_binding_serial * serial,mctp_serial_tx_fn fn,void * data)367 void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial,
368 mctp_serial_tx_fn fn, void *data)
369 {
370 serial->tx_fn = fn;
371 serial->tx_fn_data = data;
372 }
373
mctp_serial_rx(struct mctp_binding_serial * serial,const void * buf,size_t len)374 int mctp_serial_rx(struct mctp_binding_serial *serial, const void *buf,
375 size_t len)
376 {
377 mctp_rx_consume(serial, buf, len);
378 return 0;
379 }
380
mctp_serial_core_start(struct mctp_binding * binding)381 static int mctp_serial_core_start(struct mctp_binding *binding)
382 {
383 mctp_binding_set_tx_enabled(binding, true);
384 return 0;
385 }
386
mctp_binding_serial_core(struct mctp_binding_serial * b)387 struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b)
388 {
389 return &b->binding;
390 }
391
mctp_serial_init(void)392 struct mctp_binding_serial *mctp_serial_init(void)
393 {
394 struct mctp_binding_serial *serial;
395
396 serial = __mctp_alloc(sizeof(*serial));
397 memset(serial, 0, sizeof(*serial));
398 serial->fd = -1;
399 serial->rx_state = STATE_WAIT_SYNC_START;
400 serial->rx_pkt = NULL;
401 serial->binding.name = "serial";
402 serial->binding.version = 1;
403 serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU);
404 serial->binding.pkt_header = 0;
405 serial->binding.pkt_trailer = 0;
406
407 serial->binding.start = mctp_serial_core_start;
408 serial->binding.tx = mctp_binding_serial_tx;
409
410 return serial;
411 }
412
mctp_serial_destroy(struct mctp_binding_serial * serial)413 void mctp_serial_destroy(struct mctp_binding_serial *serial)
414 {
415 __mctp_free(serial);
416 }
417