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