Split patty_ax25_if_recv() into specific parts

Split patty_ax25_if_recv() into the following parts:

    * patty_ax25_if_fill(), to fill the internal PHY buffer

    * patty_ax25_if_drain(), to drain the internal PHY buffer and decode
      any data present in the buffer

    * patty_ax25_if_ready(), to test if a complete frame has been
      decoded

    * patty_ax25_if_flush(), to return the final number of bytes decoded
      in the PHY buffer and reset the decoding state

Other changes:

    * Implement a finite state machine for decoding KISS traffic in
      src/tnc.c, patty_ax25_kiss_drain()

    * Refactor src/server.c, handle_iface() to use the aforementioned
      frame receive/decode methods
This commit is contained in:
XANTRONIX Development 2020-09-17 01:10:34 -05:00 committed by XANTRONIX Industrial
parent 2f5c877762
commit d5e2062dea
5 changed files with 214 additions and 171 deletions

View file

@ -35,7 +35,13 @@ typedef int (patty_ax25_if_driver_fd)(void *);
typedef int (patty_ax25_if_driver_pending)(void *);
typedef ssize_t (patty_ax25_if_driver_recv)(void *, void *, size_t);
typedef ssize_t (patty_ax25_if_driver_fill)(void *);
typedef ssize_t (patty_ax25_if_driver_drain)(void *, void *, size_t);
typedef int (patty_ax25_if_driver_ready)(void *);
typedef ssize_t (patty_ax25_if_driver_flush)(void *);
typedef ssize_t (patty_ax25_if_driver_send)(void *, const void *, size_t);
@ -44,7 +50,10 @@ typedef struct _patty_ax25_if_driver {
patty_ax25_if_driver_destroy *destroy;
patty_ax25_if_driver_fd *fd;
patty_ax25_if_driver_pending *pending;
patty_ax25_if_driver_recv *recv;
patty_ax25_if_driver_fill *fill;
patty_ax25_if_driver_drain *drain;
patty_ax25_if_driver_ready *ready;
patty_ax25_if_driver_flush *flush;
patty_ax25_if_driver_send *send;
} patty_ax25_if_driver;
@ -100,10 +109,15 @@ int patty_ax25_if_promisc_delete(patty_ax25_if *iface,
int patty_ax25_if_fd(patty_ax25_if *iface);
ssize_t patty_ax25_if_pending(patty_ax25_if *iface);
int patty_ax25_if_pending(patty_ax25_if *iface);
ssize_t patty_ax25_if_recv(patty_ax25_if *iface,
void **buf);
ssize_t patty_ax25_if_fill(patty_ax25_if *iface);
ssize_t patty_ax25_if_drain(patty_ax25_if *iface, void *buf, size_t len);
int patty_ax25_if_ready(patty_ax25_if *iface);
ssize_t patty_ax25_if_flush(patty_ax25_if *iface);
ssize_t patty_ax25_if_send(patty_ax25_if *iface,
const void *buf,

View file

@ -39,11 +39,17 @@ void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc);
size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc);
ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc);
int patty_kiss_tnc_pending(patty_kiss_tnc *tnc);
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc,
void *buf,
size_t len);
ssize_t patty_kiss_tnc_fill(patty_kiss_tnc *tnc);
ssize_t patty_kiss_tnc_drain(patty_kiss_tnc *tnc, void *buf, size_t len);
int patty_kiss_tnc_ready(patty_kiss_tnc *tnc);
ssize_t patty_kiss_tnc_flush(patty_kiss_tnc *tnc);
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void *buf, size_t len);
ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc,
const void *buf,

View file

@ -275,43 +275,45 @@ int patty_ax25_if_fd(patty_ax25_if *iface) {
return iface->driver->fd(iface->phy);
}
ssize_t patty_ax25_if_pending(patty_ax25_if *iface) {
int patty_ax25_if_pending(patty_ax25_if *iface) {
return iface->driver->pending(iface->phy);
}
ssize_t patty_ax25_if_recv(patty_ax25_if *iface,
void **buf) {
ssize_t readlen;
struct promisc_frame frame;
ssize_t patty_ax25_if_fill(patty_ax25_if *iface) {
return iface->driver->fill(iface->phy);
}
if ((readlen = iface->driver->recv(iface->phy,
iface->rx_buf,
iface->mru)) < 0) {
goto error_driver_recv;
} else if (readlen == 0) {
goto done;
}
ssize_t patty_ax25_if_drain(patty_ax25_if *iface, void *buf, size_t len) {
return iface->driver->drain(iface->phy, buf, len);
}
*buf = iface->rx_buf;
int patty_ax25_if_ready(patty_ax25_if *iface) {
return iface->driver->ready(iface->phy);
}
ssize_t patty_ax25_if_flush(patty_ax25_if *iface) {
ssize_t len = iface->driver->flush(iface->phy);
if (len > 0) {
struct promisc_frame frame = {
.buf = iface->rx_buf,
.len = len,
.iface = iface
};
iface->stats.rx_frames++;
iface->stats.rx_bytes += readlen;
frame.buf = iface->rx_buf;
frame.len = readlen;
frame.iface = iface;
iface->stats.rx_bytes += len;
if (patty_dict_each(iface->promisc_fds,
handle_promisc_frame,
&frame) < 0) {
goto error_handle_promisc_frame;
}
}
done:
return readlen;
return len;
error_handle_promisc_frame:
error_driver_recv:
return -1;
}

View file

@ -2007,18 +2007,15 @@ error_decode:
static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) {
int fd = patty_ax25_if_fd(iface);
ssize_t len;
if (!FD_ISSET(fd, &server->fds_r)) {
goto done;
}
do {
void *buf;
ssize_t readlen;
if ((readlen = patty_ax25_if_recv(iface, &buf)) < 0) {
if ((len = patty_ax25_if_fill(iface)) < 0) {
goto error_io;
} else if (readlen == 0) {
} else if (len == 0) {
close(fd);
fd_clear(server, fd);
@ -2026,14 +2023,30 @@ static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) {
goto done;
}
if (handle_frame(server, iface, buf, readlen) < 0) {
while (1) {
ssize_t len;
if ((len = patty_ax25_if_drain(iface, iface->rx_buf, iface->mru)) < 0) {
goto error_io;
}
} while (patty_ax25_if_pending(iface));
if (!patty_ax25_if_ready(iface)) {
break;
}
if ((len = patty_ax25_if_flush(iface)) < 0) {
goto error_io;
}
if (handle_frame(server, iface, iface->rx_buf, len) < 0) {
goto error_handle_frame;
}
}
done:
return 0;
error_handle_frame:
error_io:
return -1;
}

218
src/tnc.c
View file

@ -16,18 +16,18 @@
#include "config.h"
enum state_flags {
STATE_NONE = 0,
STATE_FRAME = 1 << 0,
STATE_COMMAND = 1 << 1,
STATE_ESCAPE = 1 << 2
};
enum tnc_opts {
TNC_NONE = 0,
TNC_CLOSE_ON_DESTROY = 1 << 0
};
enum state {
KISS_NONE,
KISS_FRAME,
KISS_FRAME_BODY,
KISS_FRAME_ESCAPE
};
struct _patty_kiss_tnc {
struct termios attrs,
attrs_old;
@ -35,14 +35,15 @@ struct _patty_kiss_tnc {
int fd,
opts;
void *buf,
*frame;
void *buf;
enum state state;
size_t bufsz,
offset,
readlen,
offset_i,
offset_o,
dropped;
ssize_t readlen;
};
patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) {
@ -144,10 +145,12 @@ patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) {
}
tnc->opts = TNC_NONE;
tnc->state = KISS_NONE;
tnc->bufsz = PATTY_KISS_TNC_BUFSZ;
tnc->offset = 0;
tnc->offset_i = 0;
tnc->offset_o = 0;
tnc->dropped = 0;
tnc->readlen = -1;
tnc->readlen = 0;
return tnc;
@ -191,8 +194,10 @@ int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) {
}
static void tnc_drop(patty_kiss_tnc *tnc) {
tnc->offset = 0;
tnc->readlen = -1;
tnc->state = KISS_NONE;
tnc->offset_i = 0;
tnc->offset_o = 0;
tnc->readlen = 0;
tnc->dropped++;
}
@ -200,132 +205,132 @@ size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) {
return tnc->dropped;
}
ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc) {
if (tnc->readlen < 0) {
return -1;
}
if (tnc->offset == 0) {
return 0;
}
return tnc->readlen - tnc->offset;
int patty_kiss_tnc_pending(patty_kiss_tnc *tnc) {
return tnc->offset_i < tnc->readlen? 1: 0;
}
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc,
void *buf,
size_t len) {
size_t o = 0; /* Number of bytes written to buf */
int flags = STATE_NONE;
if (tnc->offset == tnc->readlen) {
errno = 0;
return 0;
ssize_t patty_kiss_tnc_fill(patty_kiss_tnc *tnc) {
if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) {
goto error_read;
}
while (1) {
tnc->offset_i = 0;
return tnc->readlen;
error_read:
return -1;
}
ssize_t patty_kiss_tnc_drain(patty_kiss_tnc *tnc, void *buf, size_t len) {
size_t offset_start = tnc->offset_i;
while (tnc->offset_i < tnc->readlen) {
uint8_t c;
if (o == len) {
if (tnc->offset_o == len) {
tnc_drop(tnc);
flags &= ~STATE_FRAME;
o = 0;
}
if (tnc->offset == 0) {
if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) {
goto error_io;
} else if (tnc->readlen == 0) {
goto done;
}
}
c = ((uint8_t *)tnc->buf)[tnc->offset_i++];
c = ((uint8_t *)tnc->buf)[tnc->offset++];
if (tnc->offset == tnc->readlen) {
tnc->offset = 0;
}
if (!(flags & STATE_FRAME)) {
switch (tnc->state) {
case KISS_NONE:
if (c == PATTY_KISS_FEND) {
flags = STATE_FRAME;
continue;
} else {
errno = EIO;
goto error_io;
tnc->state = KISS_FRAME;
}
} else {
break;
case KISS_FRAME:
if (c == PATTY_KISS_FEND) {
flags = STATE_NONE;
if (o > 0) {
goto done;
}
continue;
}
}
if (!(flags & STATE_COMMAND)) {
if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) {
break;
} else if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) {
errno = EIO;
goto error_io;
}
flags |= STATE_COMMAND;
tnc->state = KISS_FRAME_BODY;
continue;
}
break;
if (!(flags & STATE_ESCAPE)) {
case KISS_FRAME_BODY:
if (c == PATTY_KISS_FESC) {
flags |= STATE_ESCAPE;
tnc->state = KISS_FRAME_ESCAPE;
} else if (c == PATTY_KISS_FEND) {
tnc->state = KISS_FRAME;
continue;
}
goto done;
} else {
switch (c) {
case PATTY_KISS_TFEND:
((uint8_t *)buf)[o++] = PATTY_KISS_FEND;
flags &= ~STATE_ESCAPE;
continue;
((uint8_t *)buf)[tnc->offset_o++] = c;
}
case PATTY_KISS_TFESC:
((uint8_t *)buf)[o++] = PATTY_KISS_FESC;
flags &= ~STATE_ESCAPE;
continue;
break;
default:
case KISS_FRAME_ESCAPE:
if (c == PATTY_KISS_TFEND) {
((uint8_t *)buf)[tnc->offset_o++] = PATTY_KISS_FEND;
} else if (c == PATTY_KISS_TFESC) {
((uint8_t *)buf)[tnc->offset_o++] = PATTY_KISS_FESC;
} else {
errno = EIO;
goto error_io;
}
}
((uint8_t *)buf)[o++] = c;
tnc->state = KISS_FRAME_BODY;
}
}
done:
if (flags & STATE_FRAME) {
tnc_drop(tnc);
errno = 0;
return 0;
}
return (ssize_t)o;
return tnc->offset_i - offset_start;
error_io:
return -1;
}
int patty_kiss_tnc_ready(patty_kiss_tnc *tnc) {
return tnc->state == KISS_FRAME && tnc->offset_o > 0? 1: 0;
}
ssize_t patty_kiss_tnc_flush(patty_kiss_tnc *tnc) {
if (patty_kiss_tnc_ready(tnc)) {
ssize_t ret = (ssize_t)tnc->offset_o;
tnc->state = KISS_NONE;
tnc->offset_o = 0;
return ret;
}
return 0;
}
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void *buf, size_t len) {
while (!patty_kiss_tnc_ready(tnc)) {
ssize_t drained;
if ((drained = patty_kiss_tnc_drain(tnc, buf, len)) < 0) {
goto error_drain;
} else if (drained == 0) {
ssize_t filled;
if ((filled = patty_kiss_tnc_fill(tnc)) < 0) {
goto error_fill;
} else if (filled == 0) {
return 0;
}
}
}
return patty_kiss_tnc_flush(tnc);
error_drain:
error_fill:
return -1;
}
ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc,
const void *buf,
size_t len) {
@ -338,7 +343,10 @@ patty_ax25_if_driver *patty_kiss_tnc_driver() {
.destroy = (patty_ax25_if_driver_destroy *)patty_kiss_tnc_destroy,
.fd = (patty_ax25_if_driver_fd *)patty_kiss_tnc_fd,
.pending = (patty_ax25_if_driver_pending *)patty_kiss_tnc_pending,
.recv = (patty_ax25_if_driver_recv *)patty_kiss_tnc_recv,
.fill = (patty_ax25_if_driver_fill *)patty_kiss_tnc_fill,
.drain = (patty_ax25_if_driver_drain *)patty_kiss_tnc_drain,
.ready = (patty_ax25_if_driver_ready *)patty_kiss_tnc_ready,
.flush = (patty_ax25_if_driver_flush *)patty_kiss_tnc_flush,
.send = (patty_ax25_if_driver_send *)patty_kiss_tnc_send
};