2015-07-14 22:27:42 -05:00
|
|
|
#include <stdlib.h>
|
2015-07-16 00:31:27 +00:00
|
|
|
#include <string.h>
|
2020-05-26 23:41:39 -04:00
|
|
|
#include <inttypes.h>
|
2015-07-14 22:27:42 -05:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2015-07-14 16:45:03 +00:00
|
|
|
#include <sys/types.h>
|
2015-07-14 22:27:42 -05:00
|
|
|
#include <sys/stat.h>
|
2015-07-14 16:45:03 +00:00
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2015-07-12 02:16:26 -05:00
|
|
|
#include <patty/kiss.h>
|
|
|
|
|
|
|
|
enum kiss_flags {
|
2020-05-27 18:17:00 -04:00
|
|
|
KISS_NONE = 0,
|
|
|
|
KISS_FRAME = 1 << 0,
|
|
|
|
KISS_COMMAND = 1 << 1,
|
|
|
|
KISS_ESCAPE = 1 << 2
|
2015-07-12 02:16:26 -05:00
|
|
|
};
|
|
|
|
|
2015-07-14 22:27:42 -05:00
|
|
|
struct _patty_kiss_tnc {
|
2020-05-26 23:52:06 -04:00
|
|
|
int fd;
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
void *buf,
|
|
|
|
*frame;
|
2020-05-26 23:52:06 -04:00
|
|
|
|
|
|
|
size_t bufsz,
|
2020-05-28 17:53:26 -04:00
|
|
|
offset,
|
2020-05-26 23:52:06 -04:00
|
|
|
dropped;
|
2020-05-28 17:53:26 -04:00
|
|
|
|
|
|
|
ssize_t readlen,
|
|
|
|
left;
|
|
|
|
|
|
|
|
int eof;
|
2015-07-14 22:27:42 -05:00
|
|
|
};
|
|
|
|
|
2020-05-27 22:22:42 -04:00
|
|
|
patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd) {
|
2015-07-14 22:27:42 -05:00
|
|
|
patty_kiss_tnc *tnc;
|
|
|
|
|
|
|
|
if ((tnc = malloc(sizeof(*tnc))) == NULL) {
|
|
|
|
goto error_malloc_tnc;
|
|
|
|
}
|
|
|
|
|
2020-05-27 22:22:42 -04:00
|
|
|
if ((tnc->buf = malloc(PATTY_KISS_BUFSZ)) == NULL) {
|
2015-07-14 22:27:42 -05:00
|
|
|
goto error_malloc_buf;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:35:23 -04:00
|
|
|
tnc->fd = fd;
|
2020-05-27 22:22:42 -04:00
|
|
|
tnc->bufsz = PATTY_KISS_BUFSZ;
|
2020-05-28 17:53:26 -04:00
|
|
|
tnc->offset = 0;
|
2020-05-26 23:52:06 -04:00
|
|
|
tnc->dropped = 0;
|
2020-05-28 17:53:26 -04:00
|
|
|
tnc->readlen = 0;
|
|
|
|
tnc->left = 0;
|
|
|
|
tnc->eof = 0;
|
2015-07-14 22:27:42 -05:00
|
|
|
|
|
|
|
return tnc;
|
|
|
|
|
|
|
|
error_malloc_buf:
|
|
|
|
free(tnc);
|
|
|
|
|
|
|
|
error_malloc_tnc:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-05-27 22:22:42 -04:00
|
|
|
patty_kiss_tnc *patty_kiss_tnc_open(const char *device) {
|
2020-05-27 18:35:23 -04:00
|
|
|
patty_kiss_tnc *tnc;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if ((fd = open(device, O_RDWR)) < 0) {
|
|
|
|
goto error_open;
|
|
|
|
}
|
|
|
|
|
2020-05-27 22:22:42 -04:00
|
|
|
if ((tnc = patty_kiss_tnc_open_fd(fd)) == NULL) {
|
2020-05-27 18:35:23 -04:00
|
|
|
goto error_tnc_open_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tnc;
|
|
|
|
|
|
|
|
error_tnc_open_fd:
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
error_open:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-07-29 22:28:44 -05:00
|
|
|
int patty_kiss_tnc_fd_unix(patty_kiss_tnc *tnc) {
|
|
|
|
return tnc->fd;
|
|
|
|
}
|
|
|
|
|
2015-07-14 22:27:42 -05:00
|
|
|
void patty_kiss_tnc_close(patty_kiss_tnc *tnc) {
|
|
|
|
close(tnc->fd);
|
2015-07-15 20:29:50 -05:00
|
|
|
free(tnc->buf);
|
|
|
|
free(tnc);
|
2015-07-14 22:27:42 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
static void tnc_drop(patty_kiss_tnc *tnc) {
|
2020-05-28 17:53:26 -04:00
|
|
|
tnc->offset = 0;
|
|
|
|
tnc->readlen = 0;
|
|
|
|
tnc->left = 0;
|
|
|
|
tnc->eof = 0;
|
2020-05-27 18:17:00 -04:00
|
|
|
tnc->dropped++;
|
|
|
|
}
|
2015-07-17 00:45:14 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) {
|
|
|
|
return tnc->dropped;
|
|
|
|
}
|
2020-05-27 00:22:50 -04:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc,
|
2020-05-27 19:11:25 -04:00
|
|
|
void *buf,
|
|
|
|
size_t len,
|
2020-05-27 18:17:00 -04:00
|
|
|
int *port) {
|
2020-05-28 17:53:26 -04:00
|
|
|
size_t r = 0, /* Number of bytes read */
|
|
|
|
w = 0; /* Number of bytes written to buf */
|
2015-07-16 00:31:27 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
enum kiss_flags flags = KISS_NONE;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
if (tnc->eof) {
|
|
|
|
return 0;
|
2020-05-27 18:17:00 -04:00
|
|
|
}
|
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
while (1) {
|
|
|
|
uint8_t c;
|
|
|
|
|
|
|
|
r++;
|
|
|
|
|
|
|
|
if (w == len) {
|
|
|
|
tnc_drop(tnc);
|
|
|
|
|
|
|
|
flags &= ~KISS_FRAME;
|
|
|
|
w = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tnc->offset == 0) {
|
|
|
|
if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) {
|
|
|
|
goto error_io;
|
|
|
|
} else if (tnc->readlen == 0) {
|
|
|
|
if (errno) {
|
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
tnc->left = tnc->readlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = ((uint8_t *)tnc->buf)[tnc->offset++];
|
|
|
|
|
|
|
|
if (tnc->offset == tnc->bufsz) {
|
|
|
|
tnc->offset = 0;
|
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
|
|
|
|
if (!(flags & KISS_FRAME)) {
|
2015-07-12 02:16:26 -05:00
|
|
|
if (c == PATTY_KISS_FEND) {
|
|
|
|
flags |= KISS_FRAME;
|
2015-07-16 00:31:27 +00:00
|
|
|
|
|
|
|
continue;
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
goto error_io;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
if (c == PATTY_KISS_FEND) {
|
2020-05-28 17:53:26 -04:00
|
|
|
if (w > 0) {
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_FRAME;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
goto done;
|
|
|
|
}
|
2015-07-16 00:31:27 +00:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
continue;
|
|
|
|
}
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
if (!(flags & KISS_COMMAND)) {
|
|
|
|
if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) {
|
2015-07-12 12:00:35 -05:00
|
|
|
errno = EIO;
|
|
|
|
|
2015-07-12 02:18:08 -05:00
|
|
|
goto error_io;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
*port = PATTY_KISS_COMMAND_PORT(c);
|
|
|
|
|
|
|
|
flags |= KISS_COMMAND;
|
2015-07-12 02:16:26 -05:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
if (!(flags & KISS_ESCAPE)) {
|
2015-07-12 02:16:26 -05:00
|
|
|
if (c == PATTY_KISS_FESC) {
|
|
|
|
flags |= KISS_ESCAPE;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2020-05-27 18:17:00 -04:00
|
|
|
} else {
|
|
|
|
switch (c) {
|
|
|
|
case PATTY_KISS_TFEND:
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = PATTY_KISS_FEND;
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_ESCAPE;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case PATTY_KISS_TFESC:
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = PATTY_KISS_FESC;
|
2020-05-27 18:17:00 -04:00
|
|
|
flags &= ~KISS_ESCAPE;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
default:
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
goto error_io;
|
|
|
|
}
|
2015-07-16 00:31:27 +00:00
|
|
|
}
|
2015-07-12 02:28:31 -05:00
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
((uint8_t *)buf)[w++] = c;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
done:
|
|
|
|
if (flags & KISS_FRAME) {
|
|
|
|
tnc_drop(tnc);
|
2020-05-28 17:53:26 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
tnc->left -= r;
|
|
|
|
|
|
|
|
if (tnc->readlen < tnc->bufsz && tnc->left == 0) {
|
|
|
|
tnc->eof = 1;
|
2020-05-27 18:17:00 -04:00
|
|
|
}
|
2015-07-16 00:31:27 +00:00
|
|
|
|
2020-05-28 17:53:26 -04:00
|
|
|
return (ssize_t)w;
|
2015-07-12 02:18:08 -05:00
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
2015-07-12 02:16:26 -05:00
|
|
|
}
|
2015-07-12 15:34:40 -05:00
|
|
|
|
2020-05-26 23:41:39 -04:00
|
|
|
static inline ssize_t write_byte(int fd, uint8_t c) {
|
2015-07-12 23:48:12 -05:00
|
|
|
return write(fd, &c, sizeof(c));
|
|
|
|
}
|
|
|
|
|
2020-05-27 18:57:26 -04:00
|
|
|
static inline ssize_t write_start(int fd,
|
|
|
|
enum patty_kiss_command command,
|
|
|
|
int port) {
|
|
|
|
uint8_t start[2] = {
|
|
|
|
PATTY_KISS_FEND,
|
|
|
|
((port & 0x0f) << 4) | (command & 0x0f)
|
|
|
|
};
|
|
|
|
|
|
|
|
return write(fd, start, sizeof(start));
|
2015-07-12 23:48:12 -05:00
|
|
|
}
|
|
|
|
|
2020-05-26 23:41:39 -04:00
|
|
|
static uint8_t escape_fend[2] = { PATTY_KISS_FESC, PATTY_KISS_TFEND };
|
|
|
|
static uint8_t escape_fesc[2] = { PATTY_KISS_FESC, PATTY_KISS_TFESC };
|
2020-05-22 19:34:25 -04:00
|
|
|
|
2020-05-27 18:17:00 -04:00
|
|
|
ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc,
|
|
|
|
const void *buf,
|
|
|
|
size_t len,
|
|
|
|
int port) {
|
2015-07-12 23:48:12 -05:00
|
|
|
size_t i, start = 0, end = 0;
|
2015-07-12 15:34:40 -05:00
|
|
|
|
2020-05-27 18:57:26 -04:00
|
|
|
if (write_start(tnc->fd, PATTY_KISS_DATA, port) < 0) {
|
2015-07-12 15:34:40 -05:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<len; i++) {
|
2020-05-26 23:41:39 -04:00
|
|
|
uint8_t c = ((uint8_t *)buf)[i];
|
|
|
|
uint8_t *escape = NULL;
|
2015-07-12 15:34:40 -05:00
|
|
|
|
|
|
|
switch (c) {
|
2020-05-27 18:57:59 -04:00
|
|
|
case PATTY_KISS_FEND:
|
|
|
|
escape = escape_fend;
|
|
|
|
break;
|
2015-07-12 15:34:40 -05:00
|
|
|
|
2020-05-27 18:57:59 -04:00
|
|
|
case PATTY_KISS_FESC:
|
|
|
|
escape = escape_fesc;
|
|
|
|
break;
|
2015-07-14 16:45:03 +00:00
|
|
|
|
2020-05-27 18:57:59 -04:00
|
|
|
default:
|
|
|
|
end = i + 1;
|
2015-07-14 16:45:03 +00:00
|
|
|
|
|
|
|
break;
|
2015-07-12 15:34:40 -05:00
|
|
|
}
|
|
|
|
|
2015-07-12 23:48:12 -05:00
|
|
|
if (escape) {
|
2020-05-26 23:41:39 -04:00
|
|
|
if (write(tnc->fd, ((uint8_t *)buf) + start, end - start) < 0) {
|
2015-07-12 23:48:12 -05:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
2015-07-16 00:31:27 +00:00
|
|
|
if (write(tnc->fd, escape, 2) < 0) {
|
2015-07-12 23:48:12 -05:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
escape = NULL;
|
|
|
|
start = i + 1;
|
|
|
|
end = start;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (end - start) {
|
2020-05-26 23:41:39 -04:00
|
|
|
if (write(tnc->fd, ((uint8_t *)buf) + start, end - start) < 0) {
|
2015-07-12 15:34:40 -05:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-16 00:31:27 +00:00
|
|
|
if (write_byte(tnc->fd, PATTY_KISS_FEND) < 0) {
|
2015-07-12 23:48:12 -05:00
|
|
|
goto error_io;
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
2015-07-12 15:34:40 -05:00
|
|
|
|
|
|
|
error_io:
|
|
|
|
return -1;
|
|
|
|
}
|