2015-07-25 00:26:23 -05:00
|
|
|
#include <stdio.h>
|
2015-07-24 21:49:57 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2020-07-07 17:48:18 -04:00
|
|
|
#include <unistd.h>
|
2020-07-08 15:34:24 -04:00
|
|
|
#include <termios.h>
|
2015-07-24 21:49:57 -05:00
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <patty/ax25.h>
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
static int init_tnc(patty_ax25_if *iface, patty_ax25_if_kiss_tnc_info *info) {
|
2020-06-20 19:37:03 -04:00
|
|
|
static char *prefix = "kiss";
|
|
|
|
static int number = 0;
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
iface->tnc = (info->type == PATTY_AX25_IF_KISS_TNC_INFO_FD)?
|
|
|
|
patty_kiss_tnc_new_fd(info->fd):
|
|
|
|
patty_kiss_tnc_new(info->path);
|
|
|
|
|
|
|
|
if (iface->tnc == NULL) {
|
|
|
|
goto error_kiss_tnc_new;
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
iface->type = PATTY_AX25_IF_KISS_TNC;
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2015-07-25 00:26:23 -05:00
|
|
|
snprintf(iface->name, sizeof(iface->name), "%s%d", prefix, number++);
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
return 0;
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
error_kiss_tnc_new:
|
2020-06-20 19:37:03 -04:00
|
|
|
return -1;
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
static void destroy_tnc(patty_ax25_if *iface) {
|
|
|
|
patty_kiss_tnc_destroy(iface->tnc);
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_ax25_if *patty_ax25_if_new(int opts, patty_ax25_if_info *info) {
|
2015-07-24 21:49:57 -05:00
|
|
|
patty_ax25_if *iface;
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
if ((iface = malloc(sizeof(*iface))) == NULL) {
|
|
|
|
goto error_malloc_iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(iface, '\0', sizeof(*iface));
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
if (info->addr.callsign[0] == '\0') {
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid_address;
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
if ((iface->rx_buf = malloc(PATTY_AX25_IF_BUFSZ)) == NULL) {
|
|
|
|
goto error_malloc_rx_buf;
|
|
|
|
} else {
|
|
|
|
iface->rx_bufsz = PATTY_AX25_IF_BUFSZ;
|
|
|
|
}
|
|
|
|
|
2020-06-21 01:13:33 -04:00
|
|
|
if ((iface->tx_buf = malloc(PATTY_AX25_IF_BUFSZ)) == NULL) {
|
|
|
|
goto error_malloc_tx_buf;
|
|
|
|
} else {
|
|
|
|
iface->tx_bufsz = PATTY_AX25_IF_BUFSZ;
|
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
if ((iface->aliases = patty_list_new()) == NULL) {
|
|
|
|
goto error_list_new_aliases;
|
2020-06-20 19:37:03 -04:00
|
|
|
}
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
if ((iface->promisc_fds = patty_dict_new()) == NULL) {
|
|
|
|
goto error_dict_new_promisc_fds;
|
|
|
|
}
|
|
|
|
|
2015-07-24 21:49:57 -05:00
|
|
|
switch (PATTY_AX25_IF_OPT_TYPE(opts)) {
|
2020-06-20 19:37:03 -04:00
|
|
|
case PATTY_AX25_IF_KISS_TNC:
|
2020-06-26 22:44:19 -04:00
|
|
|
if (init_tnc(iface, (patty_ax25_if_kiss_tnc_info *)info) < 0) {
|
2020-06-20 19:37:03 -04:00
|
|
|
goto error_init;
|
|
|
|
}
|
2015-07-24 21:49:57 -05:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
default:
|
2015-07-24 21:49:57 -05:00
|
|
|
errno = EINVAL;
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
goto error_invalid_if_type;
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
memcpy(&iface->addr, &info->addr, sizeof(iface->addr));
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
return iface;
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
error_invalid_if_type:
|
|
|
|
error_init:
|
2020-07-07 17:48:18 -04:00
|
|
|
patty_dict_destroy(iface->promisc_fds);
|
|
|
|
|
|
|
|
error_dict_new_promisc_fds:
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_list_destroy(iface->aliases);
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
error_list_new_aliases:
|
2020-06-21 01:13:33 -04:00
|
|
|
free(iface->tx_buf);
|
|
|
|
|
|
|
|
error_malloc_tx_buf:
|
2020-06-20 19:37:03 -04:00
|
|
|
free(iface->rx_buf);
|
|
|
|
|
|
|
|
error_malloc_rx_buf:
|
|
|
|
free(iface);
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
error_malloc_iface:
|
2020-06-26 22:44:19 -04:00
|
|
|
error_invalid_address:
|
2015-07-24 21:49:57 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void patty_ax25_if_destroy(patty_ax25_if *iface) {
|
|
|
|
switch (iface->type) {
|
2020-06-20 19:37:03 -04:00
|
|
|
case PATTY_AX25_IF_KISS_TNC:
|
2020-06-26 22:44:19 -04:00
|
|
|
destroy_tnc(iface);
|
2020-06-20 19:37:03 -04:00
|
|
|
break;
|
2015-07-24 21:49:57 -05:00
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
default:
|
|
|
|
break;
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
2020-06-20 19:37:03 -04:00
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
patty_dict_destroy(iface->promisc_fds);
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_list_destroy(iface->aliases);
|
2020-06-20 19:37:03 -04:00
|
|
|
|
2020-06-21 01:13:33 -04:00
|
|
|
free(iface->tx_buf);
|
2020-06-20 19:37:03 -04:00
|
|
|
free(iface->rx_buf);
|
|
|
|
free(iface);
|
2015-07-24 21:49:57 -05:00
|
|
|
}
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
int patty_ax25_if_addr_each(patty_ax25_if *iface,
|
2020-06-07 02:46:12 -04:00
|
|
|
int (*callback)(char *, uint8_t, void *), void *ctx) {
|
2020-07-02 17:13:19 -04:00
|
|
|
patty_list_item *item = iface->aliases->first;
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
char buf[7];
|
|
|
|
uint8_t ssid;
|
|
|
|
|
|
|
|
if (patty_ax25_ntop(&iface->addr, buf, &ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callback(buf, ssid, ctx) < 0) {
|
|
|
|
goto error_callback_addr;
|
|
|
|
}
|
|
|
|
|
2020-07-02 17:13:19 -04:00
|
|
|
while (item) {
|
|
|
|
patty_ax25_addr *addr = item->value;
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if (patty_ax25_ntop(addr, buf, &ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (callback(buf, ssid, ctx) < 0) {
|
2015-07-25 00:26:23 -05:00
|
|
|
goto error_callback;
|
|
|
|
}
|
|
|
|
|
2020-07-02 17:13:19 -04:00
|
|
|
item = item->next;
|
|
|
|
}
|
2015-07-25 00:26:23 -05:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_callback:
|
2020-06-07 02:46:12 -04:00
|
|
|
error_ntop:
|
2020-06-26 22:44:19 -04:00
|
|
|
error_callback_addr:
|
|
|
|
error_ntop_addr:
|
2015-07-25 00:26:23 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
static patty_ax25_addr *find_addr(patty_ax25_if *iface,
|
|
|
|
const char *callsign,
|
|
|
|
uint8_t ssid) {
|
2020-07-02 17:13:19 -04:00
|
|
|
patty_list_item *item = iface->aliases->first;
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
char buf[7];
|
|
|
|
uint8_t addr_ssid;
|
|
|
|
|
|
|
|
if (patty_ax25_ntop(&iface->addr, buf, &addr_ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(buf, callsign, sizeof(buf)) == 0 && addr_ssid == ssid) {
|
|
|
|
return &iface->addr;
|
|
|
|
}
|
|
|
|
|
2020-07-02 17:13:19 -04:00
|
|
|
while (item) {
|
|
|
|
patty_ax25_addr *addr = item->value;
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if (patty_ax25_ntop(addr, buf, &addr_ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(buf, callsign, sizeof(buf)) != 0) {
|
2020-07-02 17:13:19 -04:00
|
|
|
goto next;
|
2015-07-25 00:26:23 -05:00
|
|
|
}
|
2020-06-07 02:46:12 -04:00
|
|
|
|
|
|
|
if (addr_ssid != ssid) {
|
2020-07-02 17:13:19 -04:00
|
|
|
goto next;
|
2015-07-25 00:26:23 -05:00
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
return addr;
|
2020-07-02 17:13:19 -04:00
|
|
|
next:
|
|
|
|
item = item->next;
|
2015-07-25 00:26:23 -05:00
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
error_ntop:
|
2020-06-26 22:44:19 -04:00
|
|
|
error_ntop_addr:
|
2015-07-25 00:26:23 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
int patty_ax25_if_addr_add(patty_ax25_if *iface,
|
2020-06-07 02:46:12 -04:00
|
|
|
const char *callsign,
|
|
|
|
uint8_t ssid) {
|
|
|
|
patty_ax25_addr *addr;
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if (find_addr(iface, callsign, ssid) != NULL) {
|
2015-07-25 00:26:23 -05:00
|
|
|
errno = EEXIST;
|
|
|
|
|
|
|
|
goto error_exists;
|
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if ((addr = malloc(sizeof(*addr))) == NULL) {
|
|
|
|
goto error_malloc_addr;
|
2015-07-25 00:26:23 -05:00
|
|
|
}
|
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if (patty_ax25_pton(callsign, ssid, addr) < 0) {
|
|
|
|
goto error_pton;
|
|
|
|
}
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
if ((patty_list_append(iface->aliases, addr)) == NULL) {
|
2015-07-25 00:26:23 -05:00
|
|
|
goto error_list_append;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_list_append:
|
2020-06-07 02:46:12 -04:00
|
|
|
error_pton:
|
|
|
|
free(addr);
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
error_malloc_addr:
|
2015-07-25 00:26:23 -05:00
|
|
|
error_exists:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
int patty_ax25_if_addr_delete(patty_ax25_if *iface,
|
2020-06-07 02:46:12 -04:00
|
|
|
const char *callsign,
|
|
|
|
uint8_t ssid) {
|
2020-06-26 22:44:19 -04:00
|
|
|
patty_list_item *item = iface->aliases->first;
|
2015-07-25 00:26:23 -05:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (item) {
|
2020-06-07 02:46:12 -04:00
|
|
|
char buf[7];
|
|
|
|
uint8_t addr_ssid;
|
|
|
|
|
|
|
|
patty_ax25_addr *addr = item->value;
|
|
|
|
|
|
|
|
if (patty_ax25_ntop(addr, buf, &addr_ssid, sizeof(buf)) < 0) {
|
|
|
|
goto error_ntop;
|
|
|
|
}
|
2015-07-25 00:26:23 -05:00
|
|
|
|
2020-06-07 02:46:12 -04:00
|
|
|
if (strncmp(buf, callsign, sizeof(buf)) == 0 && addr_ssid == ssid) {
|
2020-06-26 22:44:19 -04:00
|
|
|
if (patty_list_splice(iface->aliases, i) == NULL) {
|
2015-07-25 00:26:23 -05:00
|
|
|
goto error_list_splice;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
item = item->next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_list_splice:
|
2020-06-07 02:46:12 -04:00
|
|
|
error_ntop:
|
2015-07-25 00:26:23 -05:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
int patty_ax25_if_promisc_add(patty_ax25_if *iface,
|
|
|
|
int fd) {
|
2020-07-08 17:12:40 -04:00
|
|
|
if (patty_dict_get(iface->promisc_fds, (uint32_t)fd)) {
|
2020-07-07 17:48:18 -04:00
|
|
|
errno = EEXIST;
|
|
|
|
|
|
|
|
goto error_exists;
|
|
|
|
}
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
if (patty_dict_set(iface->promisc_fds,
|
|
|
|
(uint32_t)fd,
|
|
|
|
NULL + fd) == NULL) {
|
2020-07-07 17:48:18 -04:00
|
|
|
errno = ENOMEM;
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
goto error_dict_set;
|
2020-07-07 17:48:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
error_dict_set:
|
2020-07-07 17:48:18 -04:00
|
|
|
error_exists:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_ax25_if_promisc_delete(patty_ax25_if *iface,
|
|
|
|
int fd) {
|
2020-07-08 17:12:40 -04:00
|
|
|
if (patty_dict_delete(iface->promisc_fds,
|
|
|
|
(uint32_t)fd) < 0) {
|
2020-07-07 17:48:18 -04:00
|
|
|
errno = ENOENT;
|
|
|
|
|
|
|
|
goto error_notfound;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_notfound:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct promisc_frame {
|
|
|
|
const void *buf;
|
|
|
|
size_t len;
|
|
|
|
patty_ax25_if *iface;
|
|
|
|
};
|
|
|
|
|
2020-07-08 17:12:40 -04:00
|
|
|
static int handle_promisc_frame(uint32_t key,
|
2020-07-07 17:48:18 -04:00
|
|
|
void *value,
|
|
|
|
void *ctx) {
|
2020-07-08 17:12:40 -04:00
|
|
|
int fd = (int)key;
|
2020-07-07 17:48:18 -04:00
|
|
|
struct promisc_frame *frame = ctx;
|
|
|
|
|
2020-07-08 15:34:24 -04:00
|
|
|
if (write(fd, frame->buf, frame->len) < 0) {
|
|
|
|
goto error_write;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tcdrain(fd);
|
|
|
|
|
|
|
|
error_write:
|
|
|
|
return -1;
|
2020-07-07 17:48:18 -04:00
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
ssize_t patty_ax25_if_recv(patty_ax25_if *iface,
|
|
|
|
void **buf) {
|
|
|
|
ssize_t readlen;
|
|
|
|
int port;
|
2020-07-07 17:48:18 -04:00
|
|
|
struct promisc_frame frame;
|
2020-06-20 19:37:03 -04:00
|
|
|
|
|
|
|
if ((readlen = patty_kiss_tnc_recv(iface->tnc,
|
|
|
|
iface->rx_buf,
|
|
|
|
iface->rx_bufsz,
|
|
|
|
&port)) < 0) {
|
|
|
|
goto error_kiss_tnc_recv;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buf = iface->rx_buf;
|
|
|
|
|
2020-06-29 00:29:05 -04:00
|
|
|
iface->stats.rx_frames++;
|
|
|
|
iface->stats.rx_bytes += readlen;
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
frame.buf = iface->rx_buf;
|
|
|
|
frame.len = readlen;
|
|
|
|
frame.iface = iface;
|
|
|
|
|
|
|
|
if (patty_dict_each(iface->promisc_fds,
|
|
|
|
handle_promisc_frame,
|
|
|
|
&frame) < 0) {
|
|
|
|
goto error_handle_promisc_frame;
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
return readlen;
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
error_handle_promisc_frame:
|
2020-06-20 19:37:03 -04:00
|
|
|
error_kiss_tnc_recv:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_if_send(patty_ax25_if *iface,
|
|
|
|
const void *buf,
|
|
|
|
size_t len) {
|
|
|
|
ssize_t wrlen;
|
2020-07-07 17:48:18 -04:00
|
|
|
struct promisc_frame frame;
|
2020-06-20 19:37:03 -04:00
|
|
|
|
|
|
|
if ((wrlen = patty_kiss_tnc_send(iface->tnc, buf, len, 0)) < 0) {
|
|
|
|
goto error_kiss_tnc_send;
|
|
|
|
}
|
|
|
|
|
2020-06-29 00:29:05 -04:00
|
|
|
iface->stats.tx_frames++;
|
|
|
|
iface->stats.tx_bytes += wrlen;
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
frame.buf = buf;
|
|
|
|
frame.len = wrlen;
|
|
|
|
frame.iface = iface;
|
|
|
|
|
|
|
|
if (patty_dict_each(iface->promisc_fds,
|
|
|
|
handle_promisc_frame,
|
|
|
|
&frame) < 0) {
|
|
|
|
goto error_handle_promisc_frame;
|
|
|
|
}
|
|
|
|
|
2020-06-20 19:37:03 -04:00
|
|
|
return wrlen;
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
error_handle_promisc_frame:
|
2020-06-20 19:37:03 -04:00
|
|
|
error_kiss_tnc_send:
|
|
|
|
return -1;
|
|
|
|
}
|