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, 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 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 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 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 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 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 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 } 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, ((const uint8_t *)buf)[i]); 321 } 322 323 #ifdef MCTP_HAVE_FILEIO 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: %s", 334 strerror(errno)); 335 return -1; 336 } 337 338 mctp_rx_consume(serial, serial->rxbuf, len); 339 340 return 0; 341 } 342 343 int mctp_serial_init_pollfd(struct mctp_binding_serial *serial, 344 struct pollfd *pollfd) 345 { 346 pollfd->fd = serial->fd; 347 pollfd->events = POLLIN; 348 349 return 0; 350 } 351 352 int mctp_serial_open_path(struct mctp_binding_serial *serial, 353 const char *device) 354 { 355 serial->fd = open(device, O_RDWR); 356 if (serial->fd < 0) 357 mctp_prerr("can't open device %s: %s", device, strerror(errno)); 358 359 return 0; 360 } 361 362 void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd) 363 { 364 serial->fd = fd; 365 } 366 #endif 367 368 void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial, 369 mctp_serial_tx_fn fn, void *data) 370 { 371 serial->tx_fn = fn; 372 serial->tx_fn_data = data; 373 } 374 375 int mctp_serial_rx(struct mctp_binding_serial *serial, const void *buf, 376 size_t len) 377 { 378 mctp_rx_consume(serial, buf, len); 379 return 0; 380 } 381 382 static int mctp_serial_core_start(struct mctp_binding *binding) 383 { 384 mctp_binding_set_tx_enabled(binding, true); 385 return 0; 386 } 387 388 struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b) 389 { 390 return &b->binding; 391 } 392 393 struct mctp_binding_serial *mctp_serial_init(void) 394 { 395 struct mctp_binding_serial *serial; 396 397 serial = __mctp_alloc(sizeof(*serial)); 398 memset(serial, 0, sizeof(*serial)); 399 serial->fd = -1; 400 serial->rx_state = STATE_WAIT_SYNC_START; 401 serial->rx_pkt = NULL; 402 serial->binding.name = "serial"; 403 serial->binding.version = 1; 404 serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU); 405 serial->binding.pkt_header = 0; 406 serial->binding.pkt_trailer = 0; 407 408 serial->binding.start = mctp_serial_core_start; 409 serial->binding.tx = mctp_binding_serial_tx; 410 411 return serial; 412 } 413 414 void mctp_serial_destroy(struct mctp_binding_serial *serial) 415 { 416 __mctp_free(serial); 417 } 418