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