diff --git a/include/patty/kiss.h b/include/patty/kiss.h index ca3e0ec..69d71a9 100644 --- a/include/patty/kiss.h +++ b/include/patty/kiss.h @@ -35,20 +35,15 @@ int patty_kiss_tnc_fd_unix(patty_kiss_tnc *tnc); void patty_kiss_tnc_close(patty_kiss_tnc *tnc); -void patty_kiss_tnc_drop(patty_kiss_tnc *tnc); - size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc); -void patty_kiss_tnc_flush(patty_kiss_tnc *tnc, size_t len); - -ssize_t patty_kiss_tnc_buffer(patty_kiss_tnc *tnc); - -ssize_t patty_kiss_tnc_decode(patty_kiss_tnc *tnc, void *frame, size_t *len, int *port); - ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, - void **frame, int *port); + void **frame, + int *port); ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, - const void *frame, size_t len, int port); + const void *frame, + size_t len, + int port); #endif /* _PATTY_KISS_H */ diff --git a/src/kiss.c b/src/kiss.c index eff4fe3..8ddb9dd 100644 --- a/src/kiss.c +++ b/src/kiss.c @@ -11,9 +11,10 @@ #include enum kiss_flags { - KISS_NONE = 0x00, - KISS_FRAME = 0x01, - KISS_ESCAPE = 0x02 + KISS_NONE = 0, + KISS_FRAME = 1 << 0, + KISS_COMMAND = 1 << 1, + KISS_ESCAPE = 1 << 2 }; struct _patty_kiss_tnc { @@ -21,8 +22,8 @@ struct _patty_kiss_tnc { int fd; - void *frame, - *buf; + void *buf, + *frame; size_t bufsz, buflen, @@ -79,132 +80,35 @@ void patty_kiss_tnc_close(patty_kiss_tnc *tnc) { free(tnc); } -ssize_t patty_kiss_tnc_buffer(patty_kiss_tnc *tnc) { - size_t fillsz = tnc->bufsz - tnc->buflen; - ssize_t readlen = 0; +static ssize_t tnc_buffer(patty_kiss_tnc *tnc) { + ssize_t readlen; - /* - * If the buffer needs to be filled, then fill it. - */ - if (fillsz) { - void *dest = ((uint8_t *)tnc->buf) + tnc->buflen; - - if ((readlen = read(tnc->fd, dest, fillsz)) < 0) { - errno = EIO; - - goto error_io; - } - - tnc->buflen += readlen; + if (tnc->buflen == tnc->bufsz) { + goto full; } + if ((readlen = read(tnc->fd, tnc->buf, tnc->bufsz - tnc->buflen)) < 0) { + goto error_read; + } + + tnc->buflen += readlen; + return readlen; -error_io: +full: + return 0; + +error_read: return -1; } -ssize_t patty_kiss_tnc_decode(patty_kiss_tnc *tnc, void *frame, size_t *len, int *port) { - size_t i, b; - enum kiss_flags flags = KISS_NONE; +static void tnc_flush(patty_kiss_tnc *tnc, size_t len) { + memmove(tnc->buf, ((uint8_t *)tnc->buf) + len, tnc->buflen - len); - /* - * The default port is always zero, unless a command byte issued from the - * TNC in the first byte of the frame body. - */ - *port = 0; - - /* - * Ah, yes, the icky state machine wherein we unescape things off the wire - * and whatnot. - */ - for (i=0, b=0; ibuflen; i++) { - uint8_t c = ((uint8_t *)tnc->buf)[i]; - - if (i == 0) { - if (c != PATTY_KISS_FEND) { - /* - * If the first byte is not a frame end, then that's a bad thing. - */ - errno = EIO; - - goto error_io; - } - } else if (i == 1) { - if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { - errno = EIO; - - goto error_io; - } - - *port = PATTY_KISS_COMMAND_PORT(c); - - continue; - } - - if ((flags & KISS_FRAME) == 0) { - if (c == PATTY_KISS_FEND) { - flags |= KISS_FRAME; - - continue; - } - - errno = EIO; - - goto error_io; - } - - if (flags & KISS_ESCAPE) { - if (c == PATTY_KISS_TFEND) { - ((uint8_t *)frame)[b++] = PATTY_KISS_FEND; - } else if (c == PATTY_KISS_TFESC) { - ((uint8_t *)frame)[b++] = PATTY_KISS_FESC; - } else { - errno = EIO; - - goto error_io; - } - - flags &= ~KISS_ESCAPE; - - continue; - } - - if (flags & KISS_FRAME) { - if (c == PATTY_KISS_FESC) { - flags |= KISS_ESCAPE; - - continue; - } else if (c == PATTY_KISS_FEND) { - break; - } - - ((uint8_t *)frame)[b++] = c; - } - } - - /* - * Return empty-handed if we do not have a fully book-ended frame. - */ - if ((flags & KISS_FRAME) == 0) { - *len = 0; - *port = 0; - - return 0; - } - - *len = b; - - return i; - -error_io: - return -1; + tnc->buflen -= len; } -void patty_kiss_tnc_drop(patty_kiss_tnc *tnc) { - memset(tnc->buf, '\0', tnc->bufsz); - memset(tnc->frame, '\0', tnc->bufsz); - +static void tnc_drop(patty_kiss_tnc *tnc) { tnc->buflen = 0; tnc->dropped++; } @@ -213,63 +117,97 @@ size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) { return tnc->dropped; } -void patty_kiss_tnc_flush(patty_kiss_tnc *tnc, size_t len) { - /* - * Move everything from the buffer not processed up to this point, to the - * beginning of the buffer. - */ - memmove(tnc->buf, ((uint8_t *)tnc->buf) + len, tnc->buflen - len); +ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, + void **frame, + int *port) { + size_t i = 0, + b = 0; - /* - * Then, decrement the buffer length by the number of bytes already - * processed. - */ - tnc->buflen -= len; -} + enum kiss_flags flags = KISS_NONE; -ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void **frame, int *port) { - ssize_t buffered, decoded; - size_t framelen; + if (tnc_buffer(tnc) < 0) { + goto error_io; + } - /* - * Initialize the frame to be returned to the caller. - */ - memset(tnc->frame, '\0', tnc->bufsz); + while (i < tnc->buflen) { + uint8_t c = ((uint8_t *)tnc->buf)[i++]; - do { - /* - * Fill the buffer with something to parse. - */ - if ((buffered = patty_kiss_tnc_buffer(tnc)) < 0) { - goto error_io; + if (!(flags & KISS_FRAME)) { + if (c == PATTY_KISS_FEND) { + flags |= KISS_FRAME; + + continue; + } else { + errno = EIO; + + goto error_io; + } + } else { + if (c == PATTY_KISS_FEND) { + if (b > 0) { + flags &= ~KISS_FRAME; + + goto done; + } + + continue; + } } - /* - * Try to decode the TNC buffer into the frame. - */ - if ((decoded = patty_kiss_tnc_decode(tnc, tnc->frame, &framelen, port)) < 0) { - patty_kiss_tnc_drop(tnc); + if (!(flags & KISS_COMMAND)) { + if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { + errno = EIO; - goto error_io; + goto error_io; + } + + *port = PATTY_KISS_COMMAND_PORT(c); + + flags |= KISS_COMMAND; + + continue; } - /* - * If we can no longer buffer nor decode any data, then drop the whole - * frame. - */ - if (decoded == 0 && buffered == 0) { - patty_kiss_tnc_drop(tnc); + if (!(flags & KISS_ESCAPE)) { + if (c == PATTY_KISS_FESC) { + flags |= KISS_ESCAPE; + + continue; + } + } else { + switch (c) { + case PATTY_KISS_TFEND: + ((uint8_t *)tnc->frame)[b++] = PATTY_KISS_FEND; + flags &= ~KISS_ESCAPE; + continue; + + case PATTY_KISS_TFESC: + ((uint8_t *)tnc->frame)[b++] = PATTY_KISS_FESC; + flags &= ~KISS_ESCAPE; + continue; + + default: + errno = EIO; + + goto error_io; + } } - } while (decoded == 0); - /* - * Flush the buffer up to the point of the next frame start. - */ - patty_kiss_tnc_flush(tnc, decoded); + ((uint8_t *)tnc->frame)[b++] = c; + } - *frame = tnc->frame; +done: + if (flags & KISS_FRAME) { + tnc_drop(tnc); - return framelen; + *frame = NULL; + } else { + tnc_flush(tnc, i); + + *frame = tnc->frame; + } + + return (ssize_t)b; error_io: return -1; @@ -286,7 +224,10 @@ static inline ssize_t write_command(int fd, int command, int port) { static uint8_t escape_fend[2] = { PATTY_KISS_FESC, PATTY_KISS_TFEND }; static uint8_t escape_fesc[2] = { PATTY_KISS_FESC, PATTY_KISS_TFESC }; -ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, const void *buf, size_t len, int port) { +ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, + const void *buf, + size_t len, + int port) { size_t i, start = 0, end = 0; if (write_byte(tnc->fd, PATTY_KISS_FEND) < 0) {