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 { 222 mctp_prdebug("invalid revision 0x%02x", c); 223 serial->rx_state = STATE_WAIT_SYNC_START; 224 } 225 break; 226 case STATE_WAIT_LEN: 227 if (c > serial->binding.pkt_size || 228 c < sizeof(struct mctp_hdr)) { 229 mctp_prdebug("invalid size %d", c); 230 serial->rx_state = STATE_WAIT_SYNC_START; 231 } else { 232 mctp_serial_start_packet(serial, 0); 233 pkt = serial->rx_pkt; 234 serial->rx_exp_len = c; 235 serial->rx_state = STATE_DATA; 236 } 237 break; 238 239 case STATE_DATA: 240 if (c == MCTP_SERIAL_ESCAPE) { 241 serial->rx_state = STATE_DATA_ESCAPED; 242 } else { 243 mctp_pktbuf_push(pkt, &c, 1); 244 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len) 245 serial->rx_state = STATE_WAIT_FCS1; 246 } 247 break; 248 249 case STATE_DATA_ESCAPED: 250 c ^= 0x20; 251 mctp_pktbuf_push(pkt, &c, 1); 252 if (pkt->end - pkt->mctp_hdr_off == serial->rx_exp_len) 253 serial->rx_state = STATE_WAIT_FCS1; 254 else 255 serial->rx_state = STATE_DATA; 256 break; 257 258 case STATE_WAIT_FCS1: 259 serial->rx_fcs = c << 8; 260 serial->rx_state = STATE_WAIT_FCS2; 261 break; 262 case STATE_WAIT_FCS2: 263 serial->rx_fcs |= c; 264 /* todo: check fcs */ 265 serial->rx_state = STATE_WAIT_SYNC_END; 266 break; 267 268 case STATE_WAIT_SYNC_END: 269 if (c == MCTP_SERIAL_FRAMING_FLAG) { 270 mctp_serial_finish_packet(serial, true); 271 } else { 272 mctp_prdebug("missing end frame marker"); 273 mctp_serial_finish_packet(serial, false); 274 } 275 serial->rx_state = STATE_WAIT_SYNC_START; 276 break; 277 } 278 279 mctp_prdebug(" -> state: %d", serial->rx_state); 280 } 281 static void mctp_rx_consume(struct mctp_binding_serial *serial, const void *buf, 282 size_t len) 283 { 284 size_t i; 285 286 for (i = 0; i < len; i++) 287 mctp_rx_consume_one(serial, *(uint8_t *)(buf + i)); 288 } 289 290 #ifdef MCTP_HAVE_FILEIO 291 int mctp_serial_read(struct mctp_binding_serial *serial) 292 { 293 ssize_t len; 294 295 len = read(serial->fd, serial->rxbuf, sizeof(serial->rxbuf)); 296 if (len == 0) 297 return -1; 298 299 if (len < 0) { 300 mctp_prerr("can't read from serial device: %m"); 301 return -1; 302 } 303 304 mctp_rx_consume(serial, serial->rxbuf, len); 305 306 return 0; 307 } 308 309 int mctp_serial_init_pollfd(struct mctp_binding_serial *serial, 310 struct pollfd *pollfd) 311 { 312 pollfd->fd = serial->fd; 313 pollfd->events = POLLIN; 314 315 return 0; 316 } 317 318 int mctp_serial_open_path(struct mctp_binding_serial *serial, 319 const char *device) 320 { 321 serial->fd = open(device, O_RDWR); 322 if (serial->fd < 0) 323 mctp_prerr("can't open device %s: %m", device); 324 325 return 0; 326 } 327 328 void mctp_serial_open_fd(struct mctp_binding_serial *serial, int fd) 329 { 330 serial->fd = fd; 331 } 332 #endif 333 334 void mctp_serial_set_tx_fn(struct mctp_binding_serial *serial, 335 mctp_serial_tx_fn fn, void *data) 336 { 337 serial->tx_fn = fn; 338 serial->tx_fn_data = data; 339 } 340 341 int mctp_serial_rx(struct mctp_binding_serial *serial, const void *buf, 342 size_t len) 343 { 344 mctp_rx_consume(serial, buf, len); 345 return 0; 346 } 347 348 static int mctp_serial_core_start(struct mctp_binding *binding) 349 { 350 mctp_binding_set_tx_enabled(binding, true); 351 return 0; 352 } 353 354 struct mctp_binding *mctp_binding_serial_core(struct mctp_binding_serial *b) 355 { 356 return &b->binding; 357 } 358 359 struct mctp_binding_serial *mctp_serial_init(void) 360 { 361 struct mctp_binding_serial *serial; 362 363 serial = __mctp_alloc(sizeof(*serial)); 364 memset(serial, 0, sizeof(*serial)); 365 serial->fd = -1; 366 serial->rx_state = STATE_WAIT_SYNC_START; 367 serial->rx_pkt = NULL; 368 serial->binding.name = "serial"; 369 serial->binding.version = 1; 370 serial->binding.pkt_size = MCTP_PACKET_SIZE(MCTP_BTU); 371 serial->binding.pkt_header = 0; 372 serial->binding.pkt_trailer = 0; 373 374 serial->binding.start = mctp_serial_core_start; 375 serial->binding.tx = mctp_binding_serial_tx; 376 377 return serial; 378 } 379 380 void mctp_serial_destroy(struct mctp_binding_serial *serial) 381 { 382 __mctp_free(serial); 383 } 384