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:
parent
2f5c877762
commit
d5e2062dea
5 changed files with 214 additions and 171 deletions
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
44
src/if.c
44
src/if.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
29
src/server.c
29
src/server.c
|
@ -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
218
src/tnc.c
|
@ -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
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue